Link Cut Tree
题目背景
动态树
题目描述
给定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。
输入输出格式
输入格式:
第1行两个整数,分别为n和m,代表点数和操作数。
第2行到第n+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。
第n+2行到第n+m+1行,每行三个整数,分别代表操作类型和操作所需的量。
输出格式:
对于每一个0号操作,你须输出x到y的路径上点权的xor和。
输入输出样例
说明
数据范围: 1$ leq $ N,M $ leq $ 3 · $ 10^5 $
分析:
Link Cut Tree模板题。具体的知识点这位大佬已经讲的特别好了,推荐这位大佬的博客<http://www.cnblogs.com/flashhu/p/8324551.html>,蒟蒻就只放代码了。
Code:
//It is made by HolseLee on 27th June 2018 //Luogu.org P3690 #include<bits/stdc++.h> using namespace std; const int N=3e5+7; int n,m,val[N]; struct LCT{ int fa[N],ch[N][2],xr[N],sign[N],q[N],top; inline void pushup(int u) { xr[u]=xr[ch[u][0]]^xr[ch[u][1]]^val[u]; } inline void change(int u) { int temp=ch[u][0]; ch[u][0]=ch[u][1]; ch[u][1]=temp; sign[u]^=1; } inline void pushdown(int u) { if(!sign[u])return; if(ch[u][0])change(ch[u][0]); if(ch[u][1])change(ch[u][1]); sign[u]=0; } inline bool isroot(int u) { return (ch[fa[u]][0]!=u&&ch[fa[u]][1]!=u); } inline void rotate(int x) { int y=fa[x],z=fa[y]; int k=(ch[y][1]==x); int w=ch[x][k^1]; if(!isroot(y))ch[z][ch[z][1]==y]=x; ch[x][k^1]=y;ch[y][k]=w; if(w)fa[w]=y;fa[y]=x;fa[x]=z; pushup(y);pushup(x); } inline void splay(int x) { top=1;q[top]=x; for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i]; while(top)pushdown(q[top--]); while(!isroot(x)){ int y=fa[x],z=fa[y]; if(!isroot(y)) (ch[y][0]==x)^(ch[z][0]==y)?rotate(x):rotate(y); rotate(x); } } void access(int u) { for(int i=0;u;i=u,u=fa[u]){ splay(u);ch[u][1]=i;pushup(u);} } void makeroot(int u) { access(u);splay(u);change(u); } inline int find(int u) { access(u);splay(u); while(ch[u][0])pushdown(u),u=ch[u][0]; //splay(u); return u; } void split(int u,int v) { makeroot(u);access(v);splay(v); } void cut(int u,int v) { makeroot(u); if(find(v)==u&&fa[u]==v&&!ch[u][1]){ fa[u]=ch[v][0]=0;pushup(v);} } void link(int u,int v) { makeroot(u); if(find(v)!=u)fa[u]=v; } }T; inline int read() { char ch=getchar();int num=0;bool flag=false; while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();} while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} return flag?-num:num; } int main() { n=read();m=read();int opt,x,y; for(int i=1;i<=n;i++){ val[i]=read();T.xr[i]=val[i];} for(int i=1;i<=m;i++){ opt=read();x=read();y=read(); if(opt==0){ T.split(x,y); printf("%d ",T.xr[y]);} else if(opt==1){T.link(x,y);} else if(opt==2){T.cut(x,y);} else if(opt==3){ T.splay(x);val[x]=y;T.pushup(x);} } return 0; }