LCT
填坑。
就是可以维护树上动态删边加边,链操作的数据结构。整体思想就是维护一个实链剖分,每个实链按深度用splay来维护。
有以下基本操作:
1.access(x),就是把根到x都搞成实链。直接自底向上,把当前splay接到上面splay的右儿子。
2.getroot(x) ,找x所在的根。access完以后把x splay到 splay的根,一直往左儿子找即可(因为根深度最小)。
3.makeroot(x) ,将x定为根。access后发现其它关系不变,x到根的这一段翻转了,直接splay x到根然后翻转splay。
4.link(x,y),先判它们是否已连接。暴力makeroot(x),让fa[x]=y
5.split(x,y),将x到y单独拉出来作为一个splay。直接makeroot(x)再access(y),splay一下就行。(链修改查询也用这个)
5.cut(x,y) split 完硬断开就行。
luogu模板
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;
const int N = 2e5 + 5;
int ch[N][2], val[N], sum[N], fa[N], siz[N], n, m, tag[N];
inline int read() {
register int s = 0;
register char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
return s;
}
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define isRight(x) (ch[fa[x]][1]==x)
inline bool nroot(int x) { return ls(fa[x]) == x || rs(fa[x]) == x; }
inline void update(int x) { siz[x] = siz[ls(x)] + siz[rs(x)] + 1; sum[x] = sum[ls(x)] ^ sum[rs(x)] ^ val[x]; }
inline void pushdown(int x) { if (tag[x]) swap(ls(x), rs(x)); tag[ls(x)] ^= tag[x]; tag[rs(x)] ^= tag[x]; tag[x] = 0; }
inline void rotate(int x) {
int f = fa[x]; int ff = fa[f], c = isRight(x); if (nroot(f)) ch[ff][isRight(f)] = x;
ch[f][c] = ch[x][c ^ 1]; fa[ch[x][c ^ 1]] = f; ch[x][c ^ 1] = f;
fa[f] = x; fa[x] = ff; update(f); update(x);
}
inline void splay(int x) {
stack<int> st; st.push(x); for (int i = x; nroot(i); i = fa[i]) st.push(fa[i]);
while (!st.empty()) pushdown(st.top()), st.pop();
for (int f = fa[x]; nroot(x); rotate(x), f = fa[x])
if (nroot(f)) rotate((isRight(f) ^ isRight(x)) ? x : f);
update(x);
}
inline void access(int x) { for (int i = 0; x; x = fa[i = x]) splay(x), rs(x) = i, update(x); }
inline int getroot(int x) { access(x); splay(x); while (ls(x)) pushdown(x), x = ls(x); splay(x); return x; }
inline void makeroot(int x) { access(x); splay(x); tag[x] ^= 1; }
inline void link(int x, int y) { if (getroot(x) != getroot(y)) makeroot(x), fa[x] = y; }
inline void split(int x, int y) { makeroot(x); access(y); splay(y); }
inline void cut(int x, int y) {
if (getroot(x) == getroot(y)) {
split(x, y);
if (ch[y][isRight(x) ^ 1] || fa[x] != y || rs(x)) return ;
fa[x] = ls(y) = 0; update(y);
}
}
inline void modify(int x, int y) { val[x] = y; access(x); splay(x); update(x); }
inline int query(int x, int y) { split(x, y); return sum[y]; }
int main() {
n = read(); m = read();
for (int i = 1; i <= n; ++i) val[i] = sum[i] = read();
int opt, x, y;
while (m--) {
opt = read(); x = read(); y = read();
if (opt == 0) printf("%d\n", query(x, y));
else if (opt == 1) link(x, y);
else if (opt == 2) cut(x, y);
else if (opt == 3) modify(x, y);
} return 0;
}