隐藏页面特效

树链剖分【产品说明书】

一种暴论:树链剖分 = 多叉树上分块 + 线段树


1|0适用范围


总之就是数据结构的基础问题。
总的来说,树链剖分可以在O(mlogn)的时间复杂度中,解决大多数树上路径问题,包括其修改、维护和查询。

例如这样的一道模板题

又例如……(请直接跳到本文最后一章)


2|0产品简介


树链剖分有两种:重链剖分,长链剖分。(按照剖分树的方式区分)

重链剖分中有如下一些定义:

重儿子:除叶子节点外,每个点的儿子中,子树最大(即子树节点最多)的子节点。(每个节点只有一个)
轻儿子:除叶子节点外,每个点的儿子中,不是重儿子的节点。(每个节点可能有不止一个)
重边:除叶子节点外,两端点都是重儿子的边。它用于构成重链。
轻边:除叶子节点外,每个节点到其轻儿子的边。它起到连接重链的作用。
重链:一些重边连成的链。
轻链:一些轻边连成的链。

而长链剖分,相当于将重链剖分中“子树大小”的部分替换为了“子树深度”,例如:

长儿子:除叶子节点外,每个点的儿子中,子树最深(即子树的层数最大)

综上,树链剖分是对树进行剖分,最终使其变成一些线性且不相交的链的算法。这时候,对树的操作,就变成了在链上的操作。
链可是经常作为部分分存在的好东西啊


3|0生效原理


关于它的性质和实现方式。

3|1树链剖分的性质


每个节点只能属于一条链,如果每次都选择节点更多的分支建链,建出的链自然会更长,从而,链的数量也就会更少。

由此,对于重链剖分,有这样的性质:
从根节点到任意一个叶子只需要经过O(log2n)条重链。
(因为每条轻边意味着树的大小至少缩小了一半。所以整棵树中,轻边的数量是O(log2n)的。而两条重链必然由轻边连接。)

它的另一个性质是:每条重链的DFS序是连续且有序的。
这一性质使重链得以被线段树维护。对于树上区间的修改查询问题,它“继承”了线段树的优势。

3|2树链剖分的实现


详见代码解析(指路


4|0使用范例


4|1DFS序与线段树


我们知道两个性质:

  1. 每条重链内的DFS编号连续且有序
  2. 每棵子树内的DFS编号连续且有序

所以以DFS编号建立线段树。则同一条重链的节点,在线段树上是一个连续区间。

4|2路径上的修改与查询


假设给出节点xy,要修改/查询xy最短路径上节点的权值。

这其实类似于求LCA的过程。(毕竟树上最短路径嘛)而这个过程又类似于ST表求LCA的过程。
不妨假设x链头深度更深,设dfn[u]表示节点u的dfs编号。

修改

首先,令x沿重链向上跳到链头。修改这段路径中的节点权值。(对应线段树中区间为[dfn[x],dfn[]

然后将x跳到上方的重链,并再次执行上一操作。重复这两步,直到xy的链头深度相同。

然后将xy同时向上跳(类似上两步的方法),直到它们处于同一条重链之中。此时再修改xy之间的节点即可。(对应线段树中区间为[dfn[x],dfn[y]]

过程中的每次修改,直接调用update函数即可。

查询

路径查询和路径修改一模一样。只需要把update函数换成query函数。
(甚至可以用同一个求LCA函数实现查询&修改)

4|3子树里的修改与查询


子树里的操作相比于路径更加简单。
一棵子树中节点的DFS序是连续且有序的,所以可以直接用线段树进行操作(当然,提前处理子树的lr



完结撒花!

__EOF__

本文作者Meteor2008
本文链接https://www.cnblogs.com/meteor2008/p/17760360.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   _kilo-meteor  阅读(5)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示