题意:
有N个节点,M个操作:连接两个节点、单个节点的权值增加v、节点所在的连通块的所有节点的权值增加v、所有节点的权值增加v、询问节点当前的权值、询问节点所在的连通块中权值最大的节点的权值、询问所有节点中权值最大的节点的权值。N,M≤300000
题解:
可并堆,虽然听说配对堆非常快,但教程太少了不会写,所以去学了斜堆,比较好写。斜堆实际上是一棵二叉树,核心是合并操作,这是一个递归过程,有点像treap的删除操作。斜堆保证复杂度的方法是每次递归合并右节点,合并完后交换左右节点,使整棵树和splay一样,可以“自动”平衡,也是玄学。要修改整个连通块,打标记就行了。这道题特殊的一点在于询问所有节点权值的最大值,可以用STL的set维护所有连通块的根节点,当连边和修改权值时如果根节点被修改需要维护一下set。
代码:
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #include <set>
5 #define inc(i,j,k) for(int i=j;i<=k;i++)
6 #define maxn 300100
7 #define INF 0x3fffffff
8 using namespace std;
9
10 int fa[maxn],ch[maxn][2],tg[maxn],v[maxn],n,m,add;
11 multiset <int> st;
12 void pushdown(int x){
13 if(tg[x]){
14 if(ch[x][0])tg[ch[x][0]]+=tg[x],v[ch[x][0]]+=tg[x];
15 if(ch[x][1])tg[ch[x][1]]+=tg[x],v[ch[x][1]]+=tg[x];
16 tg[x]=0;
17 }
18 }
19 int dt[maxn],dts;
20 int find(int x){
21 dt[dts=1]=x; while(fa[x])x=fa[x],dt[++dts]=x;
22 for(int i=dts;i>=1;i--)pushdown(dt[i]); return x;
23 }
24 int merge(int x,int y){
25 if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); pushdown(x);
26 ch[x][1]=merge(ch[x][1],y); fa[ch[x][1]]=x; swap(ch[x][0],ch[x][1]); return x;
27 }
28 int del(int x){
29 int t=merge(ch[x][0],ch[x][1]),f=fa[x]; fa[x]=ch[x][0]=ch[x][1]=0;
30 fa[t]=f; if(f)ch[f][ch[f][1]==x]=t; return t;
31 }
32 void update1(int x,int val){
33 int y=find(x); int t=del(x); v[x]+=val;
34 if(y!=x){
35 int z=merge(y,x); st.erase(st.find(v[y])); st.insert(v[z]);
36 }else{
37 if(t){
38 int z=merge(t,x); st.erase(st.find(v[x]-val)),st.insert(v[z]);
39 }else st.erase(st.find(v[x]-val)),st.insert(v[x]);
40 }
41 }
42 void update2(int x,int val){
43 x=find(x); tg[x]+=val; v[x]+=val; if(!fa[x])st.erase(st.find(v[x]-val)),st.insert(v[x]);
44 }
45 void update3(int val){add+=val;}
46 int query1(int x){find(x); return v[x];}
47 int query2(int x){int y=find(x); return v[y];}
48 int query3(){return * --st.find(INF);}
49 void connect(int x,int y){
50 int xx=find(x),yy=find(y); if(xx==yy)return; int z=merge(xx,yy);
51 if(z==xx)st.erase(st.find(v[yy]));else st.erase(st.find(v[xx]));
52 }
53 char opt[3];
54 int main(){
55 //freopen("test.txt","r",stdin);
56 scanf("%d",&n); add=0; st.clear();
57 inc(i,1,n){
58 scanf("%d",&v[i]); st.insert(v[i]); fa[i]=ch[i][0]=ch[i][1]=tg[i]=0;
59 }
60 scanf("%d",&m);
61 inc(i,1,m){
62 scanf("%s",opt); int x,y;
63 if(opt[0]=='U')scanf("%d%d",&x,&y),connect(x,y);
64 if(opt[0]=='A'){
65 if(opt[1]=='1')scanf("%d%d",&x,&y),update1(x,y);
66 if(opt[1]=='2')scanf("%d%d",&x,&y),update2(x,y);
67 if(opt[1]=='3')scanf("%d",&x),update3(x);
68 }
69 if(opt[0]=='F'){
70 if(opt[1]=='1')scanf("%d",&x),printf("%d\n",query1(x)+add);
71 if(opt[1]=='2')scanf("%d",&x),printf("%d\n",query2(x)+add);
72 if(opt[1]=='3')printf("%d\n",query3()+add);
73 }
74 //if(i==2)break;
75 }
76 return 0;
77 }
20160530
来源:https://www.cnblogs.com/YuanZiming/p/5658709.html