【MOBAN】一份普通的LCT动态树模板 P3690 【模板】动态树(Link Cut Tree)
LuoguP3690动态树
题目描述
给定 n 个点以及每个点的权值,要你处理接下来的 m 个操作。
操作有四种,操作从 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。
输入格式
第一行两个整数,分别为 n 和 m,代表点数和操作数。
接下来 n 行,每行一个整数,第 (i+1) 行的整数 ai 表示节点 i 的权值。
接下来 m 行,每行三个整数,分别代表操作类型和操作所需的量。
输出格式
对于每一个 0 号操作,你须输出一行一个整数,表示 x 到 y 的路径上点权的 xor 和。
输入输出样例
输入 #1
3 3
1
2
3
1 1 2
0 1 2
0 1 1
输出 #1
3
1
输入 #2
5 14
114
514
19
19
810
1 1 2
0 1 2
2 1 2
1 1 2
1 2 3
2 1 3
1 1 3
1 4 5
1 2 5
0 3 5
0 3 4
3 5 233333
0 1 5
0 2 5
输出 #2
624
315
296
232709
232823
说明/提示
数据规模与约定
对于全部的测试点,保证:
- 1≤n≤105,1≤m≤3×105,1≤ai≤109。
- 对于操作 0,1,2,保证 1≤x,y≤n。
- 对于操作 3,保证 1≤x≤n,1≤y≤109。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int n, m;
int xo[maxn], sm[maxn], rev[maxn], fa[maxn];
int son[maxn][2];
static bool isroot(int x) { return son[fa[x]][0] != x && son[fa[x]][1] != x; }
void putup(int p) { sm[p] = xo[p] ^ sm[son[p][0]] ^ sm[son[p][1]]; }
void rotate(int x) {
int y = fa[x];
int z = fa[y];
int k = (son[y][1] == x);
if (!isroot(y)) {
son[z][son[z][1] == y] = x;
}
fa[x] = z;
son[y][k] = son[x][k ^ 1];
fa[son[y][k]] = y;
fa[y] = x;
son[x][k ^ 1] = y;
putup(y);
putup(x);
}
void pushdown(int p) {
if (!rev[p])
return;
swap(son[p][0], son[p][1]);
rev[son[p][0]] ^= 1, rev[son[p][1]] ^= 1;
rev[p] = 0;
}
int sta[maxn];
void splay(int x) {
int top = 0;
sta[++top] = x;
for (int i = x; !isroot(i); i = fa[i]) {
sta[++top] = fa[i];
}
while (top)
pushdown(sta[top--]);
while (!isroot(x)) {
int y = fa[x], z = fa[y];
if (!isroot(y))
((son[z][1] == y) ^ (son[y][1] == x)) ? rotate(x) : rotate(y);
rotate(x);
}
}
void acc(int x) {
for (int y = 0; x; y = x, x = fa[x]) {
splay(x);
son[x][1] = y;
putup(x);
}
}
void setroot(int x) {
acc(x);
splay(x);
rev[x] ^= 1;
}
void link(int x, int y) {
setroot(x);
fa[x] = y;
}
void cut(int x, int y) {
setroot(x);
acc(y);
splay(y);
son[y][0] = fa[x] = 0;
putup(y);
}
int main() {
// freopen("P3690_8.in", "r", stdin);
// freopen("yo.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &xo[i]);
sm[i] = xo[i];
}
int opt, x, y;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &opt, &x, &y);
if (opt == 0) {
setroot(x);
acc(y);
splay(y);
printf("%d\n", sm[y]);
} else if (opt == 1) {
setroot(x);
acc(y);
splay(y);
int p = y;
for (; son[p][0]; p = son[p][0])
;
if (p == x)
continue;
link(x, y);
} else if (opt == 2) {
setroot(x);
acc(y);
splay(y);
if (son[y][0] != x && son[y][1] != x)
continue;
cut(x, y);
} else {
acc(x);
splay(x);
xo[x] = y;
putup(x);
}
}
return 0;
}