加边,删边,询问之中怎料变幻无常;
左旋,右旋,伸展背后暗含均摊平衡。
LCT 简介
Link Cut Tree 是解决动态树相关问题的有力工具,其实准确说是维护动态的有根森林,即多棵有根树。它支持在均摊 $O(\log n)$ 的时间对森林进行以下操作:
newnode(x)
新建节点 x,这是个平凡的操作,是 $O(1)$ 的。link(x, y)
将在不同连通块的节点x
和y
之间连边。cut(x, y)
将 x, y 之间已有的边删掉。makeRoot(x)
让 x 成为其所在树的根。pathQuery(x, y)
或pathModify
,询问 x 到 y 的路径上的有结合律的信息(如路径长度,路径上节点的异或和等可以用线段树维护的信息),或者进行修改。
LCT 核心操作
Link Cut Tree 的核心是每个节点记录一个重儿子 (preferred child,应该叫偏爱儿子),节点到重儿子的边称为重边,相邻的重边形成的叫重链,LCT 要把每个重链以深度为关键字用一棵 Splay 树来维护,而各个 Splay 树之间也存在父子关系,。具体说:
Auxiliary Tree(辅助树)
由一条重链上的所有节点所构成的 Splay 称作这条链的辅助树
每个点的键值为这个点的深度,即这棵Splay的中序遍历是这条链从链顶到链底的所有节点构成的序列
辅助树的根节点的父亲指向链顶的父亲节点,然而链顶的父亲节点的儿子并不指向辅助树的根节点
(也就是说父亲不认轻儿子只认重儿子,儿子都认父亲)
这条性质为后来的操作提供了依据
原树与辅助树的关系
- 原树中的重链 -> 辅助树中两个节点位于同一棵Splay中
- 原树中的轻链 -> 辅助树中子节点所在Splay的根节点的father指向父节点
- 注意原树与辅助树的结构并不相同
- 辅助树的根节点≠原树的根节点
- 辅助树中的father≠原树中的father
辅助树是不断变化的,重链和轻链不断变化
令每个节点的重儿子 $h_v$ 如下:
$$
h_v = \begin{cases}v & \text{if }v\text{ is the last accessed vertex in its subtree}\
w &\text{if the last accessed vertex in }v \text{ ‘s subtree is in }\&w \text{‘s subtree} \end{cases}
$$
只要维护上这个,就可以解决上面不涉及换根的所有问题了。
换根怎么解决呢?
实现
1 | /* |
时间复杂度分析:
$m$ 次操作,$h_v$ 的所有改变次数加起来是 $O(m\log n)$ 的。这是因为:
$$
\begin{aligned}
\text{changes in }h_v \leq & \text{ preferred light edge created} + \
& \text{ preferred heavy edge destroyed} +\
& \text{ } n-1
\end{aligned}
$$
Access Lemma
轻重链剖分