学习博客
https://www.cnblogs.com/flashhu/p/8324551.html
题目
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m, k;
namespace LCT { // lct板子
int v[N];// 点权
int f[N];// 父节点
int st[N];//栈
int c[N][2];// 每个节点的两个儿子
// 判断节点x是否为一个splay的根
inline bool nroot(register int x) {
// 如果节点x是根 则其与其父亲节点之间连的是轻边
// 如果连的是轻边 他的父亲的儿子里没有它
return c[f[x]][0] == x || c[f[x]][1] == x;
}
int r[N];//r为区间翻转懒标记数组
#define lc c[x][0]
#define rc c[x][1]
// splay区间翻转操作
inline void pushr(register int x) {
register int t = lc;
lc = rc;
rc = t;
r[x] ^= 1;
}
// 判断并释放懒标记
inline void pushDown(register int x) {
if (r[x]) {
if (lc) pushr(lc);
if (rc) pushr(rc);
r[x] = 0;
}
}
int s[N];
// 上传信息
inline void pushUp(register int x) {
s[x] = s[lc] ^ s[rc] ^ v[x];
}
// 一次旋转
inline void rotate(register int x) {
register int y = f[x], z = f[y], k = (c[y][1] == x), w = c[x][!k];
if (nroot(y))
c[z][c[z][1] == y] = x;
c[x][!k] = y;
c[y][k] = w;
if (w)
f[w] = y;
f[y] = x;
f[x] = z;
pushUp(y);
}
inline void splay(register int x) {
register int y = x, z = 0;
st[++z] = y;//暂存当前点到根的整条路径 pushdown时一定要从上往下放标记
while (nroot(y)) st[++z] = y = f[y];
while (z) pushDown(st[z--]);
while (nroot(x)) {
y = f[x];
z = f[y];
if (nroot(y))
rotate((c[y][0] == x) ^ (c[z][0] == y) ? x : y);
rotate(x);
}
pushUp(x);
}
// 打通当前根节点到指定节点的树链
// 使得一条中序遍历以根开始、以指定点结束的splay出现
inline void access(register int x) {
for (int y = 0; x; y = x, x = f[x]) {
splay(x);
rc = y;
pushUp(x);
}
}
//换根
inline void makeRoot(register int x) {
access(x);
splay(x);
pushr(x);
}
//提取路径 拉出x->y的路径成为一个splay 然后以y为splay的根
inline void split(register int x, register int y) {
makeRoot(x);
access(y);
splay(y);
}
// 查找在真实的树中存在的根
int findRoot(register int x) {
access(x);
splay(x);
while (lc) {
pushDown(x);
x = lc;
}
splay(x);
return x;
}
// 连边
inline void link(register int x, register int y) {
makeRoot(x);
if (findRoot(y) != x) {
f[x] = y;
};
}
// 断边
inline void cut(register int x, register int y) {
makeRoot(x);
if (findRoot(y) == x && f[y] == x && !c[y][0]) {
f[y] = c[x][1] = 0;
pushUp(x);
}
}
}
using namespace LCT;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("1.in", "r", stdin);
freopen("debug.out", "w", stdout);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
int op, x, y;
while (m--) {
cin >> op >> x >> y;
if (op == 0) { // 询问 (x->y)所有点权xor和
split(x, y);
printf("%d\n", s[y]);
} else if (op == 1) { //连通x->y
link(x, y);
} else if (op == 2) { // 删除x->y这条边
cut(x, y);
} else {//op=3 将x点权变为y
// 每次修改值的时候 需要将x转上来
splay(x);
v[x] = y;
}
}
return 0;
}