题意:
有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 ",query1(x)+add); 71 if(opt[1]=='2')scanf("%d",&x),printf("%d ",query2(x)+add); 72 if(opt[1]=='3')printf("%d ",query3()+add); 73 } 74 //if(i==2)break; 75 } 76 return 0; 77 }
20160530