[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
", 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 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8135741.html