[bzoj2333] 棘手的操作
题意:
有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<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 300010
using 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]<v[y]) swap(x,y);
pushdown(x);//2:将当前的根节点pushdown
rs[x]=merge(rs[x],y);
fa[rs[x]]=x;
swap(ls[x],rs[x]);
return x;
}
int merge2(int x, int y) {
if(!x || !y) return x+y;
if(v[x]<v[y]) swap(x,y);
rs2[x]=merge2(rs2[x],y);
fa2[rs2[x]]=x;
swap(ls2[x],rs2[x]);
return x;
}
int del(int x) {
pushdown(x);
int q=fa[x],p=merge(ls[x],rs[x]);
fa[x]=ls[x]=rs[x]=0,fa[p]=q;
if(!q) return p;//3:注意这里返回根的细节
else {
x==ls[q]?ls[q]=p:rs[q]=p;
return find(q);
}
}
void del2(int x) {
int q=fa2[x],p=merge2(ls2[x],rs2[x]);
fa2[x]=ls2[x]=rs2[x]=0,fa2[p]=q;
if(!q) rt=p;
else x==ls2[q]?ls2[q]=p:rs2[q]=p;
}
int main() {
n=gi();
for(int i=1; i<=n; i++) {
v[i]=gi(),rt=merge2(rt,i);
}
m=gi();
while(m--) {
scanf("%s", s);
if(s[0]=='U') {
int x=gi(),y=gi();
x=find(x),y=find(y);
if(x==y) continue;
if(merge(x,y)==x) del2(y);
else del2(x);
}
else if(s[0]=='A') {
if(s[1]=='1') {
int x=gi(),w=gi(),u;
u=find(x),del2(u);
v[x]+=w+sum(x);
u=merge(x,del(x)),rt=merge2(rt,u);//1:合并x和删除x后的连通块
}
else if(s[1]=='2') {
int x=gi(),w=gi();
x=find(x),del2(x);
v[x]+=w,lazy[x]+=w;
rt=merge2(rt,x);
}
else all+=gi();
}
else {
if(s[1]=='1') {
int x=gi();
printf("%d\n", v[x]+sum(x)+all);
}
else if(s[1]=='2') {
int x=gi();
printf("%d\n", v[find(x)]+all);
}
else printf("%d\n", v[rt]+all);
}
}
return 0;
}