LCT
前言
LCT(Link Cut Tree) 支持在森林中动态加边、删边、维护链上信息的数据结构。基于 Splay 和实虚链剖分。请确保你对链剖分以及 Splay 有所了解。
实虚链剖分
同轻重链剖分,每个节点都有实虚两种属性。每个节点最多有 $1$ 个实儿子,从父亲到实儿子的边称为实边,从父亲到虚儿子的边称为虚边,一条由实边构成的极长的链称为实链。与轻重链剖分不同的是节点的实虚是动态指定的,并且一个点所有的儿子可以都是虚儿子。
LCT 维护的是一个 Splay 森林。每一棵 Splay 中维护的是一条实链,Splay 中序遍历得到的序列满足在原树中深度严格从小到大。而虚边则是由虚儿子所在的 Splay 的根指向父亲节点。注意对于每条虚边并不会被父亲记录下来(认父不认子)。在考虑虚边的情况下若干个 Splay 连成一个树,称为辅助树。每个辅助树唯一对应一棵树,但一棵树有很多种可能的辅助树。我们仅需维护辅助树上的信息就可以维护原树信息。
一个例子(实边为实线,虚边为虚线,左侧为原树,右侧为辅助树):
LCT
一些变量及辅助函数定义
1 |
|
fa
记录在辅助树中的父亲节点(注意:辅助树中的父亲节点不一定是原树中的父亲)。ch[0]
是 Splay 中的左儿子,ch[1]
是 Splay 的右儿子。isrs
判断该节点是否是其父亲的右儿子。nroot
判断该节点是否不是其所在 Splay 的根,根据如果是虚边,则不是其父亲的左右儿子即可判断。
信息维护相关函数
1 |
|
LCT 需要用到区间翻转。push_r
表示将以 $x$ 为根的子树翻转,rev
是翻转标记。push_down
下放标记,根据题目要求有可能还需要在此下放别的标记。push_up
更新信息,需要根据题目自行维护。
rotate
1 |
|
将节点 $x$ 和其父亲进行旋转。与普通 Splay 不同的是需要判断 $x$ 节点的父亲是否是这棵 Splay 的根,避免将虚儿子的错误地放到实儿子的位置。
splay
1 |
|
将 $x$ 旋转至 Splay 的根。由于有翻转操作,所以必须把从节点 $x$ 到这个 Splay 的根的路径上所有标记下放才能得到位置正确的左右儿子。需要从上到下下放,用一个栈辅助。请使用双旋 Splay 而不是单旋 Spaly 以保证复杂度。
access
1 |
|
LCT 核心操作。将 $x$ 至当前根的路径变为一条实链,且该实链上没有除这条路径外的其他节点。从 $x$ 开始跳虚边。设当前已经处理到 $y$,先把 $y$ 转至 Splay 的根,将其在辅助树上父亲也转至根,此时父亲的右儿子是原来的实儿子,只需将右儿子替换为 $y$ 就将一条虚边变为实边,然后从 $y$ 的父亲继续向上处理。注意:在最开始的时候 $x$ 的所有儿子都要变为虚儿子,即将 $x$ 的右子树变为 $0$,否则会有 $x$ 的实儿子在最终的实链中。
以 access(6)
为例
make_root
1 |
|
将 $x$ 指定为原树的根。在换根时,只有 $x$ 到当前的根节点的路径上所有点的深度顺序被翻转。所以只需要把这条路径变为一条实链,再将这条实链翻转。
find_root
1 |
|
找 $x$ 在原树中的根节点。首先将 $x$ 到根的路径变为一条实链。再将 $x$ 旋转到根方便操作。根节点在这条路径中必为深度最小的点。只需一直找左儿子即可。注意需要 push_down
,否则得到的左右儿子顺序可能相反。为了保证时间复杂度,请将找到的点旋转至根。 find_root
效率较低,如果题目可以用并查集维护联通性,请使用并查集代替 find_root
。注意:如果某些题目需要在 LCT 的 Splay 中像 find_root
一样找某些节点,请将找到的节点旋转至根以保证时间复杂度。
split
1 |
|
将 $x$ 到 $y$ 的路径变为一条实链,方便进行操作。只需将 $x$ 指定为原树的根,再将 $y$ 到根的路径变为实链。为了方便操作,一般会将 $y$ 旋转到 Splay 的根。
link
1 |
|
在 $x$ 和 $y$ 中连接一条边。新连接的边为虚边。将 $x$ 指定为原树中 $x$ 所在连通块的根。只需将 $x$ 的父亲指定为 $y$ 即可连一条虚边。在 link
时请确保 $x$ 和 $y$ 不连通。否则会导致奇怪问题。
cut
1 |
|
断开 $x$ 到 $y$ 的边。将 $x$ 到 $y$ 的路径变为一个实链,由于 $x$ 到 $y$ 有直接连边,所以 Splay 中仅有 $x$ 和 $y$ 两个节点。由于split
默认将 $x$ 指定为根,所以 $x$ 比 $y$ 深度小,必然是 $y$ 的左儿子,相互断开连接即可。$y$ 少了一个儿子需要重新更新信息。在 cut
时请确保 $x$ 和 $y$ 有直接连边,否则会导致奇怪问题。在替换树上的边时需要先 cut
再 link
,否则连边不合法。