3282: Tree
Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 2350 Solved: 1104
[Submit][Status][Discuss]Description
给定N个点以及每个点的权值,要你处理接下来的M个操作。操作有4种。操作从0到3编号。点从1到N编号。0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接。2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。3:后接两个整数(x,y),代表将点X上的权值变成Y。Input
第1行两个整数,分别为N和M,代表点数和操作数。第2行到第N+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。第N+2行到第N+M+1行,每行三个整数,分别代表操作类型和操作所需的量。1<=N,M<=300000
Output
对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。
Sample Input
3 3
1
2
3
1 1 2
0 1 2
0 1 1Sample Output
3
1HINT
Source
复习一下LCT板子。感觉异或有非常多的性质?至少异或和LCT关系比较密切。
Link-Cut Tree,一种可以支持在线维护森林以及连边,断边等森林操作的数据结构。主要难点在于区分“原树”与“Splay”树。
和Splay的区别不大,主要是Rot()和Splay()中的y!=rt改为了!isroot(y),以及Splay之前一定要记得将这棵Splay树pushdown。
注意要多upd(),修改的时候记得Splay()一下以保证期望复杂度。
for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); 感觉是最难的一句话,要记牢。
代码应该会很难调,所以要提高熟练度和静态差错的能力。
有个奇怪的地方,在结构体内定义的函数好像可以不用分先后顺序。如下面的代码,split()用到了mkroot(),但前者可以放在后者的前面。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls ch[x][0] 4 #define rs ch[x][1] 5 #define rep(i,l,r) for (int i=l; i<=r; i++) 6 using namespace std; 7 8 const int N=300100; 9 int n,Q,op,x,y; 10 11 struct LCT{ 12 int v[N],sum[N],f[N],ch[N][2],rev[N]; 13 bool isroot(int x){ return (!f[x]) || (ch[f[x]][0]!=x && ch[f[x]][1]!=x); } 14 void put(int x){ swap(ls,rs); rev[x]^=1; } 15 void push(int x){ if (rev[x]) put(ls),put(rs),rev[x]=0; } 16 void upd(int x){ sum[x]=sum[ls]^sum[rs]^v[x]; } 17 void pd(int x){ if (!isroot(x)) pd(f[x]); push(x); } 18 19 void rot(int x){ 20 int y=f[x],z=f[y],w=(ch[y][1]==x); 21 if (!isroot(y)) ch[z][ch[z][1]==y]=x; 22 f[x]=z; f[y]=x; f[ch[x][w^1]]=y; 23 ch[y][w]=ch[x][w^1]; ch[x][w^1]=y; upd(y); 24 } 25 26 void splay(int x){ 27 pd(x); 28 while (!isroot(x)){ 29 int y=f[x],z=f[y]; 30 if (!isroot(y)){ if ((ch[z][0]==y) ^ (ch[y][0]==x)) rot(x); else rot(y); } 31 rot(x); 32 } 33 upd(x); 34 } 35 36 void access(int x){ for (int y=0; x; y=x,x=f[x]) splay(x),ch[x][1]=y,upd(x); } 37 void split(int x,int y){ mkroot(x); access(y); splay(y); } 38 void mkroot(int x){ access(x); splay(x); put(x); } 39 void link(int x,int y){ mkroot(x); f[x]=y; } 40 void cut(int x,int y){ split(x,y); ch[y][0]=f[x]=0; upd(y); } 41 int find(int x){ access(x); splay(x); while (ls) x=ls; return x; } 42 }T; 43 44 int main(){ 45 freopen("bzoj3282.in","r",stdin); 46 freopen("bzoj3282.out","w",stdout); 47 scanf("%d%d",&n,&Q); 48 rep(i,1,n) scanf("%d",&T.v[i]); 49 while (Q--){ 50 scanf("%d%d%d",&op,&x,&y); 51 if (op==0) T.split(x,y),printf("%d ",T.sum[y]); 52 if (op==1) if (T.find(x)!=T.find(y)) T.link(x,y); 53 if (op==2) if (T.find(x)==T.find(y)) T.cut(x,y); 54 if (op==3) T.v[x]=y,T.splay(x); 55 } 56 return 0; 57 }