2333: [SCOI2011]棘手的操作
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2113 Solved: 820
[Submit][Status][Discuss]
Description
有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: 输出所有节点中,权值最大的节点的权值
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
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
抄了发黄学长的程序
U:直接merge,merge的时候在set里删除较小的值
A1:先把那个点删除,删除就是合并他的左右儿子,挂到他的父亲下面,然后加上修改值,再合并,修改set中的值
A2:打标记,找到根打标记,切记要更新set
A3:维护个变量就好了
F1:先把祖先的标记都传下来(有点类似lct),然后输出
F2:找到祖先,输出
F3:输出set的值
#include<bits/stdc++.h> using namespace std; #define N 600010 int n,q; multiset<int> sheap; struct heap { int all; int fa[N],tag[N],c[N],lc[N],rc[N],d[N],st[N]; int find(int x) { while(fa[x]) x=fa[x]; return x; } void pushdown(int x) { if(!tag[x]) return; if(lc[x]) c[lc[x]]+=tag[x],tag[lc[x]]+=tag[x]; if(rc[x]) c[rc[x]]+=tag[x],tag[rc[x]]+=tag[x]; tag[x]=0; } int merge(int x,int y) { // printf("x=%d y=%d ",x,y); if(!x) return y; if(!y) return x; pushdown(x); pushdown(y); if(c[x]<c[y]) swap(x,y); rc[x]=merge(rc[x],y); fa[rc[x]]=x; if(d[rc[x]]>d[lc[x]]) swap(lc[x],rc[x]); if(rc[x]) d[x]=d[rc[x]]+1; else d[x]=0; return x; } void solvetag(int x) { int top=0; st[++top]=x; while(fa[x]) { st[++top]=fa[x]; x=fa[x]; } for(int i=top;i;--i) pushdown(st[i]); } void Union(int x,int y) { int top1=find(x),top2=find(y); if(top1==top2) return; int root=merge(top1,top2); if(root==top1) sheap.erase(sheap.find(c[top2])); else sheap.erase(sheap.find(c[top1])); } int del(int x) { solvetag(x); int f=fa[x],t=merge(lc[x],rc[x]); // puts("**********************"); lc[x]=rc[x]=fa[x]=0; if(f) if(lc[f]==x) lc[f]=t; else rc[f]=t; fa[t]=f; // printf("t=%d find ",t); return find(t); } void addone(int x,int v) { solvetag(x); int top=find(x); sheap.erase(sheap.find(c[top])); c[x]+=v; int y=del(x); // printf("y=%d ",y); int root=merge(y,x); // printf("root=%d ",root); sheap.insert(c[root]); } void addtag(int x,int v) { int top=find(x); sheap.erase(sheap.find(c[top])); tag[top]+=v; c[top]+=v; sheap.insert(c[top]); } void addall(int v) { all+=v; } int getpoint(int x) { solvetag(x); return c[x]+all; } int getmax(int x) { int top=find(x); // printf("top=%d ",top); return c[top]+all; } int getallmax() { // printf("size=%d ",sheap.size()); int x=(*sheap.rbegin()); return x+all; } void print() { for(int i=1;i<=n;++i) printf("c[%d]=%d ",i,c[i]); puts(""); for(int i=1;i<=n;++i) printf("tag[%d]=%d ",i,tag[i]); puts(""); } }heap; int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&heap.c[i]),sheap.insert(heap.c[i]); scanf("%d",&q); while(q--) { char s[10]; int x,y,v; scanf("%s",s); if(s[0]=='U') { scanf("%d%d",&x,&y); heap.Union(x,y); } if(s[0]=='A') { if(s[1]=='1') { scanf("%d%d",&x,&v); heap.addone(x,v); } if(s[1]=='2') { scanf("%d%d",&x,&v); heap.addtag(x,v); } if(s[1]=='3') { scanf("%d",&v); heap.addall(v); } } if(s[0]=='F') { if(s[1]=='1') { scanf("%d",&x); printf("%d ",heap.getpoint(x)); } if(s[1]=='2') { scanf("%d",&x); printf("%d ",heap.getmax(x)); } if(s[1]=='3') printf("%d ",heap.getallmax()); } // heap.print(); } return 0; }