[Luogu 3690]【模板】Link Cut Tree (动态树)

时间:2023-03-09 22:40:48
[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$只有两个节点)。

 //It is made by Awson on 2017.12.28
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define LD long double
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 3e5; struct Link_Cut_Tree {
int ch[N+][], pre[N+], val[N+], xr[N+], isrt[N+], rev[N+];
void pushup(int o) {
if (!o) return;
xr[o] = xr[ch[o][]]^xr[ch[o][]]^val[o];
}
void pushdown(int o) {
if (!o || !rev[o]) return;
int ls = ch[o][], rs = ch[o][];
swap(ch[ls][], ch[ls][]), swap(ch[rs][], ch[rs][]);
rev[ls] ^= , rev[rs] ^= , rev[o] = ;
}
void push(int o) {
if (!isrt[o]) push(pre[o]);
pushdown(o);
}
void rotate(int o, int kind) {
int p = pre[o];
ch[p][!kind] = ch[o][kind], pre[ch[o][kind]] = p;
if (isrt[p]) isrt[o] = , isrt[p] = ;
else ch[pre[p]][ch[pre[p]][] == p] = o;
pre[o] = pre[p];
ch[o][kind] = p, pre[p] = o;
pushup(p), pushup(o);
}
void splay(int o) {
push(o);
while (!isrt[o]) {
if (isrt[pre[o]]) rotate(o, ch[pre[o]][] == o);
else {
int p = pre[o], kind = ch[pre[p]][] == p;
if (ch[p][kind] == o) rotate(o, !kind), rotate(o, kind);
else rotate(p, kind), rotate(o, kind);
}
}
}
void access(int o) {
int y = ;
while (o) {
splay(o);
xr[o] ^= xr[ch[o][]];
isrt[ch[o][]] = , isrt[ch[o][] = y] = ;
pushup(o);
o = pre[y = o];
}
}
void makeroot(int o) {
access(o), splay(o);
rev[o] ^= , swap(ch[o][], ch[o][]);
}
int find(int o) {
access(o), splay(o);
while (ch[o][]) o = ch[o][];
return o;
}
void link(int x, int y) {
int p = find(x), q = find(y);
if (p == q) return;
makeroot(x); pre[x] = y;
}
void cut(int x, int y) {
makeroot(x), access(y), splay(y);
if (ch[y][] != x) return;
xr[y] ^= xr[x], ch[y][] = pre[x] = , isrt[x] = ;
}
int query(int x, int y) {
makeroot(x), access(y), splay(y);
return xr[y];
}
void update(int o, int key) {
makeroot(o); val[o] = key; pushup(o);
}
}T;
int n, m, x, opt, y; void work() {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) {
scanf("%d", &x);
T.val[i] = T.xr[i] = x, T.isrt[i] = ;
}
while (m--) {
scanf("%d%d%d", &opt, &x, &y);
if (opt == ) printf("%d\n", T.query(x, y));
else if (opt == ) T.link(x, y);
else if (opt == ) T.cut(x, y);
else T.update(x, y);
}
}
int main() {
work();
return ;
}