题意:
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:
U x y: 加一条边,连接第x个节点和第y个节点
A1 x v: 将第x个节点的权值增加v
A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v
A3 v: 将所有节点的权值都增加v
F1 x: 输出第x个节点当前的权值
F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值
F3: 输出所有节点中,权值最大的节点的权值
题解:
可并堆(堆套堆)
看到这个题号,不做这个题真是对不起这个题了
维护两个可并堆,一个是每个连通块里的可并堆,还有一个是每个连通块的堆顶所组成的堆
由于需要修改结点,所以要用到可并堆的删除任意结点的操作,这个在hyh的论文里讲得很清楚,这个题要维护两个堆,用左偏树写起来会很蛋疼,每次要更新dis
用斜堆写代码量会小很多......所以直接斜堆了......
#include#include #include #include #include #include #define ll long long#define N 300010using namespace std;int n,m,rt,all;int v[N],lazy[N],fa[N],ls[N],rs[N],fa2[N],ls2[N],rs2[N];char s[10];int gi() { int x=0,o=1; char ch=getchar(); while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') o=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return o*x;}int find(int x) { while(fa[x]) x=fa[x]; return x;}int sum(int x) { int ret=0; while(fa[x]) ret+=lazy[fa[x]],x=fa[x]; return ret;}void pushdown(int x) { if(lazy[x]) { v[ls[x]]+=lazy[x],v[rs[x]]+=lazy[x]; lazy[ls[x]]+=lazy[x],lazy[rs[x]]+=lazy[x]; lazy[x]=0; }}int merge(int x, int y) { if(!x || !y) return x+y; if(v[x]