3282: Tree
Time Limit: 30 Sec Memory Limit: 512 MB Submit: 2350 Solved: 1104 [][][]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 #include2 #include 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\n",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 }