[Luogu 3690]【模板】Link Cut Tree (动态树)
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行,每行三个整数,分别代表操作类型和操作所需的量。
Output
对于每一个0号操作,你须输出X到Y的路径上点权的Xor和。
Sample Input
3 3
1
2
3
1 1 2
0 1 2
0 1 1
Sample Output
3
1
HINT
数据范围: $ 1 \leq N, M \leq 3 \cdot {10}^5 $
题解
维护$xor$和维护子树大小类似。
这道题用到的技巧:
找根:$access(o)$及$splay(o)$后一直往左走。最后一个节点就是根。(理由:由于$LCT$中$splay$的性质:按深度作为键值);
判断是否之间有边:再$cut$之前,判断根的左儿子是否是另外一个点。(理由:若存在边,则包含这条边的$splay$只有两个节点)。
1 //It is made by Awson on 2017.12.28 2 #include <map> 3 #include <set> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <cstdio> 10 #include <string> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define LD long double 17 #define Max(a, b) ((a) > (b) ? (a) : (b)) 18 #define Min(a, b) ((a) < (b) ? (a) : (b)) 19 using namespace std; 20 const int N = 3e5; 21 22 struct Link_Cut_Tree { 23 int ch[N+5][2], pre[N+5], val[N+5], xr[N+5], isrt[N+5], rev[N+5]; 24 void pushup(int o) { 25 if (!o) return; 26 xr[o] = xr[ch[o][0]]^xr[ch[o][1]]^val[o]; 27 } 28 void pushdown(int o) { 29 if (!o || !rev[o]) return; 30 int ls = ch[o][0], rs = ch[o][1]; 31 swap(ch[ls][0], ch[ls][1]), swap(ch[rs][0], ch[rs][1]); 32 rev[ls] ^= 1, rev[rs] ^= 1, rev[o] = 0; 33 } 34 void push(int o) { 35 if (!isrt[o]) push(pre[o]); 36 pushdown(o); 37 } 38 void rotate(int o, int kind) { 39 int p = pre[o]; 40 ch[p][!kind] = ch[o][kind], pre[ch[o][kind]] = p; 41 if (isrt[p]) isrt[o] = 1, isrt[p] = 0; 42 else ch[pre[p]][ch[pre[p]][1] == p] = o; 43 pre[o] = pre[p]; 44 ch[o][kind] = p, pre[p] = o; 45 pushup(p), pushup(o); 46 } 47 void splay(int o) { 48 push(o); 49 while (!isrt[o]) { 50 if (isrt[pre[o]]) rotate(o, ch[pre[o]][0] == o); 51 else { 52 int p = pre[o], kind = ch[pre[p]][0] == p; 53 if (ch[p][kind] == o) rotate(o, !kind), rotate(o, kind); 54 else rotate(p, kind), rotate(o, kind); 55 } 56 } 57 } 58 void access(int o) { 59 int y = 0; 60 while (o) { 61 splay(o); 62 xr[o] ^= xr[ch[o][1]]; 63 isrt[ch[o][1]] = 1, isrt[ch[o][1] = y] = 0; 64 pushup(o); 65 o = pre[y = o]; 66 } 67 } 68 void makeroot(int o) { 69 access(o), splay(o); 70 rev[o] ^= 1, swap(ch[o][0], ch[o][1]); 71 } 72 int find(int o) { 73 access(o), splay(o); 74 while (ch[o][0]) o = ch[o][0]; 75 return o; 76 } 77 void link(int x, int y) { 78 int p = find(x), q = find(y); 79 if (p == q) return; 80 makeroot(x); pre[x] = y; 81 } 82 void cut(int x, int y) { 83 makeroot(x), access(y), splay(y); 84 if (ch[y][0] != x) return; 85 xr[y] ^= xr[x], ch[y][0] = pre[x] = 0, isrt[x] = 1; 86 } 87 int query(int x, int y) { 88 makeroot(x), access(y), splay(y); 89 return xr[y]; 90 } 91 void update(int o, int key) { 92 makeroot(o); val[o] = key; pushup(o); 93 } 94 }T; 95 int n, m, x, opt, y; 96 97 void work() { 98 scanf("%d%d", &n, &m); 99 for (int i = 1; i <= n; i++) { 100 scanf("%d", &x); 101 T.val[i] = T.xr[i] = x, T.isrt[i] = 1; 102 } 103 while (m--) { 104 scanf("%d%d%d", &opt, &x, &y); 105 if (opt == 0) printf("%d\n", T.query(x, y)); 106 else if (opt == 1) T.link(x, y); 107 else if (opt == 2) T.cut(x, y); 108 else T.update(x, y); 109 } 110 } 111 int main() { 112 work(); 113 return 0; 114 }
博主蒟蒻,随意转载。但必须附上原文链接:http://www.cnblogs.com/NaVi-Awson/,否则你会终生找不到妹子!!!