题目背景
动态树
题目描述
给定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:
复制
3 3 1 2 3 1 1 2 0 1 2 0 1 1
输出样例#1:
复制
3 1
说明
数据范围: $1 \leq N, M \leq 3 \cdot {10}^5$
题解:
动态树练手。
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #define ll(x) lct[x].child[0] 9 #define rr(x) lct[x].child[1] 10 #define son(x,t) lct[x].child[t] 11 using namespace std; 12 int n,m; 13 int read(){ 14 int ans=0,f=1;char i=getchar(); 15 while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} 16 while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} 17 return ans*f; 18 } 19 struct LCT{ 20 int child[2],fa,x,size,sum,rev; 21 bool is_root; 22 }lct[300005]; 23 void push_up(int root){ 24 if(!root)return; 25 lct[root].sum=lct[root].x^lct[ll(root)].sum^lct[rr(root)].sum; 26 lct[root].size=lct[ll(root)].size+lct[rr(root)].size+1; 27 } 28 int getson(int x){ 29 return x==son(lct[x].fa,1); 30 } 31 void push_rev(int x){ 32 if(!x)return; 33 swap(ll(x),rr(x)); 34 lct[x].rev^=1; 35 } 36 void push_down(int x){ 37 if(lct[x].rev&&x){ 38 push_rev(ll(x)); 39 push_rev(rr(x)); 40 lct[x].rev^=1; 41 } 42 } 43 void push(int x){ 44 if(!lct[x].is_root)push(lct[x].fa); 45 push_down(x); 46 } 47 void rotate(int x){ 48 if(lct[x].is_root)return; 49 int fa=lct[x].fa,fafa=lct[fa].fa,t=getson(x); 50 son(fa,t)=son(x,!t);if(son(x,!t))lct[son(x,!t)].fa=fa; 51 lct[fa].fa=x;son(x,!t)=fa; 52 lct[x].fa=fafa; 53 if(!lct[fa].is_root)son(fafa,son(fafa,1)==fa)=x; 54 else lct[x].is_root=1,lct[fa].is_root=0; 55 push_up(fa); 56 push_up(x); 57 } 58 void splay(int x){ 59 push(x); 60 for(int fa;!lct[x].is_root;rotate(x)) 61 if(!lct[fa=lct[x].fa].is_root) 62 rotate(getson(fa)==getson(x)?fa:x); 63 } 64 void access(int x){ 65 int y=0; 66 while(x){ 67 splay(x); 68 lct[rr(x)].is_root=1; 69 lct[rr(x)=y].is_root=0; 70 push_up(x); 71 x=lct[y=x].fa; 72 } 73 } 74 void mroot(int x){ 75 access(x); 76 splay(x); 77 push_rev(x); 78 } 79 void link(int u,int v){ 80 mroot(u); 81 lct[u].fa=v; 82 } 83 void cut(int u,int v){ 84 mroot(u); 85 access(v);splay(v); 86 lct[son(v,0)].fa=lct[v].fa; 87 lct[son(v,0)].is_root=1; 88 ll(v)=lct[v].fa=0; 89 push_up(v); 90 } 91 int find(int x){ 92 access(x); 93 splay(x); 94 if(ll(x))x=ll(x); 95 return x; 96 } 97 int main(){ 98 int i,j; 99 n=read();m=read(); 100 for(i=1;i<=n;i++){ 101 lct[i].x=lct[i].sum=read(); 102 lct[i].size=1; 103 ll(i)=rr(i)=lct[i].fa=0; 104 lct[i].is_root=1; 105 } 106 int a,b,c; 107 for(i=1;i<=m;i++){ 108 c=read();a=read();b=read(); 109 if(c==0){ 110 mroot(a); 111 access(b); 112 splay(b); 113 printf("%d\n",lct[b].sum); 114 } 115 else if(c==1){ 116 int p=find(a),q=find(b); 117 if(p!=q)link(a,b); 118 } 119 else if(c==2){ 120 mroot(a); 121 access(b); 122 splay(b); 123 if(ll(b)==a)cut(a,b); 124 } 125 else{ 126 mroot(a); 127 splay(a); 128 lct[a].x=b; 129 push_up(a); 130 } 131 } 132 return 0; 133 }