浅谈树链剖分

定义

(不严谨的口胡)

树链剖分将一棵树按照某种方式划分成多条链,再利用一系列数据结构对链上信息进行维护。

有什么用?

详见洛谷模板P3384

支持:

  • 求\(LCA\)
  • 路径信息维护
  • 子树信息维护
  • ...

算法实现

怎么实现呢?
因为博主太菜了不会长链剖分,所以这里讲轻重链剖分
据说也有名字叫启发式剖分?

在轻重链剖分中,每个非叶节点有且仅有一个重儿子,其余子节点为轻儿子。轻重儿子划分的依据是子树大小,对于每个非叶节点, 其子树\(size\)最大的子节点成为它的重儿子,其余节点成为它的轻儿子。

放一张图

graph (1).png

红色边为重边,黑色边为轻边

性质:

  1. 每个点在且仅在一条重链上
    证明显然
  2. 对于任意轻边\(edge(u \rightarrow v)\),有\(size[v] < \frac{size[u]}{2}\)
    证明显然
  3. 一棵树从叶节点走到根节点,经过的重链至多有\(log_2(n)\)条
    证明:可以发现,经过树剖之后的图是由一些重链和连接它们的轻边组成的(必要时,一条重链也可退化成边甚至是点)。从底向上,当我们每一次走过一条重链并跨过轻边到另一条重链时,所在节点的子树大小都至少翻了一倍(见性质\((2)\)),那么最多翻\(log_2(n)\)次子树大小就会变成\(n\),即跳到根节点。
    这条性质的证明实际也是树剖复杂度为严格\(O(nlog_2(n))\)的证明

实现:

两遍dfs
第一遍\(dfs\)维护每个节点的深度\(dep\)、父亲\(fa\)、子树大小\(size\)(回溯时更新),重儿子\(son\)(在更新\(siz\)时顺便维护)


void dfs1(int cur, int fa) {
    father[cur] = fa, size[cur] = 1, dep[cur] = dep[fa] + 1;
    for (register int i = first[cur]; i; i = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值