动态树(LCT)概述
动态树(Link-Cut Tree,LCT)是一种用于维护动态森林数据结构的高效算法,支持以下操作:
- 动态连接与断开:在树之间添加或删除边。
- 路径查询与修改:对树上两点间的路径进行信息统计(如最大值、求和)或批量修改。
- 子树操作:部分变种支持子树查询。
LCT的核心思想是通过**伸展树(Splay Tree)**维护树的虚实链剖分,将操作复杂度均摊到 O(\\log n)。
LCT的核心操作
数据结构定义
每个节点存储以下信息:
python
class LCTNode:
def __init__(self, val):
self.val = val # 节点值
self.left = None # 左孩子
self.right = None # 右孩子
self.parent = None # 父节点
self.rev = False # 翻转标记(用于路径反转)
self.size = 1 # 子树大小(可选,用于维护附加信息)
基本Splay操作
Splay操作将节点旋转到当前伸展树的根,同时维护树的平衡:
python
def splay(x):
while not is_root(x):
y = x.parent
if not is_root(y):
push_down(y.parent) # 下传延迟标记
push_down(y)
push_down(x)
if not is_root(y):
if (y.parent.left == y) == (y.left == x):
rotate(y) # 同方向先转父节点
else:
rotate(x)
rotate(x)
update(x) # 更新节点信息
虚实链切换
access(x) 操作将根到 x 的路径变为实链,其他边变为虚边:
python
def access(x):
last = None
while x:
splay(x)
x.right = last # 将原有右子树变为虚边
update(x) # 更新节点信息
last = x
x = x.parent
路径反转
make_root(x) 通过反转路径将 x 设为根:
python
def make_root(x):
access(x)
splay(x)
x.rev ^= True # 打翻转标记
swap(x.left, x.right) # 实际翻转在push_down时处理
常用操作实现
连接两棵树(Link)
要求 x 和 y 不在同一棵树中:
python
def link(x, y):
make_root(x)
x.parent = y # 将x作为y的虚儿子
断开边(Cut)
要求 x 和 y 直接相连:
python
def cut(x, y):
make_root(x)
access(y)
splay(y)
y.left.parent = None # 断开x与y的边
y.left = None
update(y)
路径查询
查询 x 到 y 的路径信息(如求和):
python
def query_path(x, y):
make_root(x)
access(y)
splay(y)
return y.sum # 假设维护了sum字段
复杂度分析
- 单次操作:均摊 O(\\log n),依赖Splay树的均摊性质。
- 空间:O(n),每个节点需存储额外字段。
Python实现注意事项
- 延迟标记处理 :翻转标记(
rev)需在Splay操作前下传。 - 维护附加信息 :如路径求和、最大值等,需在
update函数中同步。 - 边界条件 :注意
is_root的判断(父节点为空或为虚边)。
完整实现需结合具体问题调整,上述代码为简化版框架。