lct 维护有根树的实链剖分, 就像重链剖分一样, 每个点都有一个实儿子和一堆虚儿子。
lct 的每个实链都用一颗独立的 splay 来维护, 节点都是原链中的节点编号, 满足二叉查找树性质的 key 值是节点在原树中的深度。另外,对于原树中的节点 x,若其在原树中的父亲的实儿子不是 x, 那么在 lct 中, x 所在的实链的 splay 的根的父节点指向 x 在原树的父亲, 另外,由于 splay 维护的是实链的信息, 那么 x 父亲并不会把 x 当作 splay 的子节点, 这就是 “认父不认子”。
lct 有一个操作 access,它是 lct 的一些特色操作的基础。access (x) 表示将原树中的根 root 到 x 的路径划分成一个独立的实链, 这个操作由于认父不认子很好实现。
【LCT模板】
模板革新!
目录
模板
【记录】
精彩摘选:(论短路运算符和下标运算符的用法)
const int MAXN = 1e5 + 5 ;
int n, m, a[MAXN] ;
int s[MAXN], pa[MAXN], ch[MAXN][2] ;
// xor_sum parent children
bool tag[MAXN] ;
inline bool is(int x) { return x[pa][ch][0] != x && x[pa][ch][1] != x;} // isroot?
inline void ud(int x) { x[s] = x[a] ^ x[ch][0][s] ^ x[ch][1][s];}// update
inline void rv(int x) {x[tag] ^= 1, std::swap(x[ch][0], x[ch][1]); }// reverse
inline void ps(int x) { x[tag] && (rv(x[ch][0]), rv(x[ch][1]), x[tag] = 0);}
// pushdown