码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2333[SCOI2011]棘手的操作

时间:2016-07-10 23:15:25      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

bzoj2333[SCOI2011]棘手的操作

题意:

有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

bzoj2333[SCOI2011]棘手的操作

标签:

原文地址:http://www.cnblogs.com/YuanZiming/p/5658709.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!