树链剖分【产品说明书】
1|0适用范围
总之就是数据结构的基础问题。
总的来说,树链剖分可以在的时间复杂度中,解决大多数树上路径问题,包括其修改、维护和查询。
例如这样的一道模板题
又例如……(请直接跳到本文最后一章)
2|0产品简介
树链剖分有两种:重链剖分,长链剖分。(按照剖分树的方式区分)
重链剖分中有如下一些定义:
重儿子:除叶子节点外,每个点的儿子中,子树最大(即子树节点最多)的子节点。(每个节点只有一个)
轻儿子:除叶子节点外,每个点的儿子中,不是重儿子的节点。(每个节点可能有不止一个)
重边:除叶子节点外,两端点都是重儿子的边。它用于构成重链。
轻边:除叶子节点外,每个节点到其轻儿子的边。它起到连接重链的作用。
重链:一些重边连成的链。
轻链:一些轻边连成的链。
而长链剖分,相当于将重链剖分中“子树大小”的部分替换为了“子树深度”,例如:
长儿子:除叶子节点外,每个点的儿子中,子树最深(即子树的层数最大)
综上,树链剖分是对树进行剖分,最终使其变成一些线性且不相交的链的算法。这时候,对树的操作,就变成了在链上的操作。
链可是经常作为部分分存在的好东西啊
3|0生效原理
关于它的性质和实现方式。
3|1树链剖分的性质
每个节点只能属于一条链,如果每次都选择节点更多的分支建链,建出的链自然会更长,从而,链的数量也就会更少。
由此,对于重链剖分,有这样的性质:
从根节点到任意一个叶子只需要经过条重链。
(因为每条轻边意味着树的大小至少缩小了一半。所以整棵树中,轻边的数量是的。而两条重链必然由轻边连接。)
它的另一个性质是:每条重链的DFS序是连续且有序的。
这一性质使重链得以被线段树维护。对于树上区间的修改查询问题,它“继承”了线段树的优势。
3|2树链剖分的实现
详见代码解析(指路)
4|0使用范例
4|1DFS序与线段树
我们知道两个性质:
- 每条重链内的DFS编号连续且有序
- 每棵子树内的DFS编号连续且有序
所以以DFS编号建立线段树。则同一条重链的节点,在线段树上是一个连续区间。
4|2路径上的修改与查询
假设给出节点,,要修改/查询到最短路径上节点的权值。
这其实类似于求LCA的过程。(毕竟树上最短路径嘛)而这个过程又类似于ST表求LCA的过程。
不妨假设链头深度更深,设表示节点的dfs编号。
修改
首先,令沿重链向上跳到链头。修改这段路径中的节点权值。(对应线段树中区间为)
然后将跳到上方的重链,并再次执行上一操作。重复这两步,直到与的链头深度相同。
然后将和同时向上跳(类似上两步的方法),直到它们处于同一条重链之中。此时再修改和之间的节点即可。(对应线段树中区间为)
过程中的每次修改,直接调用update函数即可。
查询
路径查询和路径修改一模一样。只需要把update函数换成query函数。
(甚至可以用同一个求LCA函数实现查询&修改)
4|3子树里的修改与查询
子树里的操作相比于路径更加简单。
一棵子树中节点的DFS序是连续且有序的,所以可以直接用线段树进行操作(当然,提前处理子树的和)
__EOF__

本文链接:https://www.cnblogs.com/meteor2008/p/17760360.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文来自博客园,作者:_kilo-meteor,转载请注明原文链接:https://www.cnblogs.com/meteor2008/p/17760360.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)