模板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≤N,M≤3⋅105
算法原理提供可靠网址:
这道题用到的技巧:
找根:$makeroot(o)$后一直往左走。最后一个节点就是根。(理由:由于$LCT$中$splay$的性质:按深度作为键值);
判断是否之间有边:再$cut$之前,判断根的左儿子是否是另外一个点。(理由:若存在边,则包含这条边的$splay$只有两个节点)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 int xr[300005],ch[300005][2],val[300005],pre[300005],n,m; 9 bool isrt[300005],rev[300005]; 10 void pushup(int o) 11 { 12 if (!o) return; 13 xr[o]=xr[ch[o][0]]^xr[ch[o][1]]^val[o]; 14 } 15 void pushdown(int o) 16 { 17 if (!o) return; 18 if (rev[o]) 19 { 20 int ls=ch[o][0],rs=ch[o][1]; 21 if (ls) 22 { 23 rev[ls]^=1; 24 swap(ch[ls][0],ch[ls][1]); 25 } 26 if (rs) 27 { 28 rev[rs]^=1; 29 swap(ch[rs][0],ch[rs][1]); 30 } 31 rev[o]=0; 32 } 33 } 34 void push(int o) 35 { 36 if (isrt[o]==0) 37 push(pre[o]); 38 pushdown(o); 39 } 40 void rotate(int o,bool kind) 41 { 42 int p=pre[o]; 43 ch[p][!kind]=ch[o][kind];pre[ch[o][kind]]=p; 44 if (isrt[p]) isrt[o]=1,isrt[p]=0; 45 else ch[pre[p]][ch[pre[p]][1]==p]=o; 46 pre[o]=pre[p]; 47 ch[o][kind]=p;pre[p]=o; 48 pushup(p);pushup(o); 49 } 50 void splay(int o) 51 { 52 push(o); 53 while (isrt[o]==0) 54 { 55 if (isrt[pre[o]]) 56 rotate(o,ch[pre[o]][0]==o); 57 else 58 { 59 int p=pre[o],kind=ch[pre[p]][0]==p; 60 if (ch[p][kind]==o) 61 rotate(o,!kind),rotate(o,kind); 62 else rotate(p,kind),rotate(o,kind); 63 } 64 } 65 } 66 void access(int o) 67 { 68 int y=0; 69 while (o) 70 { 71 splay(o); 72 //xr[o]^=xr[ch[o][1]]; 73 isrt[ch[o][1]]=1;isrt[ch[o][1]=y]=0; 74 pushup(o); 75 o=pre[y=o]; 76 } 77 } 78 void makeroot(int o) 79 { 80 access(o); 81 splay(o); 82 rev[o]^=1; 83 swap(ch[o][0],ch[o][1]); 84 } 85 int find(int o) 86 { 87 makeroot(o); 88 access(o);splay(o); 89 while (ch[o][0]) 90 { 91 o=ch[o][0]; 92 } 93 return o; 94 } 95 void link(int x,int y) 96 { 97 makeroot(x); 98 pre[x]=y; 99 } 100 void cut(int x,int y) 101 { 102 makeroot(x);access(y);splay(y); 103 if (ch[y][0]!=x) return; 104 pre[x]=0; 105 ch[y][0]=0; 106 isrt[x]=1; 107 pushup(y); 108 } 109 int main() 110 {int i,c,x,y; 111 cin>>n>>m; 112 for (i=1;i<=n;i++) 113 { 114 scanf("%d",&val[i]); 115 xr[i]=val[i];isrt[i]=1; 116 } 117 for (i=1;i<=m;i++) 118 { 119 scanf("%d%d%d",&c,&x,&y); 120 if (c==0) 121 { 122 makeroot(y); 123 access(x); 124 splay(x); 125 printf("%d\n",xr[x]); 126 } 127 else if (c==1) 128 { 129 int p=find(x),q=find(y); 130 if (p!=q) link(x,y); 131 } 132 else if (c==2) 133 { 134 cut(x,y); 135 } 136 else if (c==3) 137 { 138 val[x]=y; 139 makeroot(x); 140 pushup(x); 141 } 142 } 143 }