BZOJ2333:[SCOI2011]棘手的操作(Splay)

Description

N个节点,标号从1N,这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: 输出所有节点中,权值最大的节点的权值

Input

输入的第一行是一个整数N,代表节点个数。

接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。

再下一行输入一个整数Q,代表接下来的操作数。

最后输入Q行,每行的格式如题目描述所示。

Output

对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

Sample Input

3
0 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3

Sample Output

-10
10
10

HINT

对于30%的数据,保证 N<=100,Q<=10000

对于80%的数据,保证 N<=100000,Q<=100000

对于100%的数据,保证 N<=300000,Q<=300000

对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

Solution

第一眼:这不splay启发式合并板子题吗?
然后就开始漫长的写写写调调调
维护多颗splay
U:splay启发式合并,一个个删除小的splay插入到大的splay里面
A1:删除val[x],插入val[x]+v
A2:开个Add数组,维护每颗splay整体加的数
A3:搞个全局变量ALL记一下就好了
F1:直接输出val[x]+Add[x]+ALL
F2:直接输出Max[ID[x]],其中ID是x所属的平衡树编号
F3::这个相当于要维护Max[]的最大值。开个可删堆,每次Max[i]变化的时候就把旧的删掉,新的插入,F3查询的时候直接输出堆顶即可。
emmm话说为什么大部分人都写的堆啊_(Xз」∠)_

Code

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #define N (600000+1000) 
  5 using namespace std;
  6 
  7 int Son[N][2],Father[N],Size[N];
  8 int ID[N],Add[N],Val[N],Max[N];
  9 int Root[N],n,m,x,y,v,ALL;
 10 char opt[10];
 11 priority_queue<int>Heap,Del;
 12 
 13 int Get(int x){return Son[Father[x]][1]==x;}
 14 void Update(int x){Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
 15 void Clear(int x){Son[x][0]=Son[x][1]=Father[x]=Size[x]=Val[x]=0;}
 16 
 17 int Pre(int x)
 18 {
 19     x=Son[x][0];
 20     while (Son[x][1]) x=Son[x][1]; 
 21     return x;
 22 }
 23 
 24 int Get_Max(int x)
 25 {
 26     while (Son[x][1]) x=Son[x][1]; 
 27     return Val[x];
 28 }
 29 
 30 void Rotate(int x)
 31 {
 32     int wh=Get(x);
 33     int fa=Father[x], fafa=Father[fa];
 34     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
 35     Son[fa][wh]=Son[x][wh^1]; Father[fa]=x;
 36     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 37     Son[x][wh^1]=fa; Father[x]=fafa;
 38     Update(fa); Update(x);
 39 }
 40 
 41 void Splay(int x)
 42 {
 43     for (int fa; (fa=Father[x]); Rotate(x))
 44         if (Father[fa])
 45             Rotate(Get(fa)==Get(x)?fa:x);
 46     Root[ID[x]]=x;
 47 }
 48 
 49 void Insert(int x,int y,int v)
 50 {
 51     int now=Root[ID[y]],fa=0;
 52     while (1)
 53     {
 54         fa=now,now=Son[now][v>Val[now]];
 55         if (now==0) 
 56         {
 57             Val[x]=v; Size[x]=1; Father[x]=fa; ID[x]=ID[y];
 58             Son[fa][v>Val[fa]]=x; Splay(x); return;
 59         }
 60     }
 61 }
 62 
 63 void Delete(int x)
 64 {
 65     Splay(x);
 66     if (!Son[Root[ID[x]]][0] && !Son[Root[ID[x]]][1])
 67     {
 68         Clear(Root[ID[x]]);
 69         Root[ID[x]]=0;
 70         return;
 71     }
 72     if (!Son[Root[ID[x]]][0])
 73     {
 74         Root[ID[x]]=Son[Root[ID[x]]][1];
 75         Clear(Father[Root[ID[x]]]);
 76         Father[Root[ID[x]]]=0;
 77         return;
 78     }
 79     if (!Son[Root[ID[x]]][1])
 80     {
 81         Root[ID[x]]=Son[Root[ID[x]]][0];
 82         Clear(Father[Root[ID[x]]]);
 83         Father[Root[ID[x]]]=0;
 84         return;
 85     }
 86     int oldroot=Root[ID[x]];
 87     int pre=Pre(Root[ID[x]]);
 88     Splay(pre);
 89     Son[Root[ID[x]]][1]=Son[oldroot][1];
 90     Father[Son[oldroot][1]]=Root[ID[x]];
 91     Clear(oldroot);
 92     Update(Root[ID[x]]);
 93 }
 94 
 95 void Merge(int x,int y)
 96 {
 97     if (Son[x][0]) Merge(Son[x][0],y);
 98     if (Son[x][1]) Merge(Son[x][1],y);
 99     int val=Val[x]+Add[ID[x]]-Add[ID[y]]; Clear(x);
100     Insert(x,y,val); 
101 }
102 
103 int main()
104 {
105     scanf("%d",&n);
106     for (int i=1; i<=n; ++i)
107     {
108         scanf("%d",&x);
109         ID[i]=i; Val[i]=x; Max[i]=x; 
110         Root[i]=i; Size[i]=1; Heap.push(x);
111     }
112     scanf("%d",&m);
113     for (int i=1; i<=m; ++i)
114     {
115         scanf("%s",opt);
116         if (opt[0]=='U')
117         {
118             scanf("%d%d",&x,&y);
119             if (ID[x]!=ID[y]) 
120             {
121                 Del.push(min(Max[ID[x]],Max[ID[y]]));
122                 if (Size[Root[ID[x]]]>Size[Root[ID[y]]]) swap(x,y);
123                 Max[ID[y]]=max(Max[ID[y]],Max[ID[x]]);
124                 Merge(Root[ID[x]],Root[ID[y]]);
125             }
126         }
127             
128         if (opt[0]=='A' && opt[1]=='1')
129         {
130             scanf("%d%d",&x,&v);
131             int val=Val[x]+v;
132             if (Size[Root[ID[x]]]==1)
133             {
134                 Val[x]=val;
135                 Del.push(Max[ID[x]]);
136                 Max[ID[x]]=val+Add[ID[x]];
137                 Heap.push(Max[ID[x]]);
138                 continue;
139             }
140             Delete(x); Insert(x,Root[ID[x]],val);
141             Del.push(Max[ID[x]]);
142             Max[ID[x]]=Get_Max(Root[ID[x]])+Add[ID[x]];
143             Heap.push(Max[ID[x]]);
144         }
145         
146         if (opt[0]=='A' && opt[1]=='2')
147         {
148             scanf("%d%d",&x,&v), Add[ID[x]]+=v;
149             Del.push(Max[ID[x]]);
150             Max[ID[x]]=Get_Max(Root[ID[x]])+Add[ID[x]];
151             Heap.push(Max[ID[x]]);
152         }
153             
154         if (opt[0]=='A' && opt[1]=='3')
155             scanf("%d",&v),ALL+=v;
156             
157         if (opt[0]=='F' && opt[1]=='1')
158             scanf("%d",&x), printf("%d\n",Val[x]+Add[ID[x]]+ALL);
159             
160         if (opt[0]=='F' && opt[1]=='2')
161         {
162             scanf("%d",&x), printf("%d\n",Max[ID[x]]+ALL);
163         }
164         
165         if (opt[0]=='F' && opt[1]=='3')
166         {
167             while ((!Heap.empty()) && (!Del.empty()) && Heap.top()==Del.top())
168                 Heap.pop(), Del.pop();
169             printf("%d\n",Heap.top()+ALL);
170         }
171     }
172 }

转载于:https://www.cnblogs.com/refun/p/9540169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值