【学习笔记】树链剖分
1.树上差分
对于普通的序列差分,最后进行一次
但是树上差分不能这么干。因为我们进行普通差分时会让
分析一下出问题的原因出在树上一个点可以有多个儿子。从而我们会想到在树上一个点还是只有一个祖先。于是我们再想到树上非常容易出现的递归性,就能想到最后进行的应该是
所以对于
return;
对于边差分就考虑把边下放到点。对于一个边
那么这样的两条链应该拆成
注意点差分边差分修改的位置不同。
2.树上启发式合并(dsu on tree)
当题目中没有修改并且查询仅与子树有关可以考虑通过树上启发式合并来做到
定义重儿子为子树中节点最多的儿子。轻儿子是除重儿子外的儿子。一个点连向重儿子的边叫做重边,其他的叫做轻边。
考虑这样一个暴力:每次把一个子树的答案算出来,然后清空所有数组。显然复杂度是
考虑优化这个暴力。我们发现对于子树
那么我们可以考虑把最大的儿子(重儿子)留下来不删除。也就是在计算当前点的时候,先把轻儿子答案计算完,并且计算完就删掉防止和其他儿子产生冲突,然后计算重儿子答案并保留贡献,再把所有轻儿子贡献加回来得到当前答案。
实现的话我们给函数多加上一个布尔值代表这一次的数据需不需要保留。然后后面给轻儿子加贡献就写一个新的函数。
复杂度是
- 证明:
考虑一个点会被计算的次数。如果它位于
考虑一条边是轻边,那么节点数至少乘以
3.重链剖分
重链是连续的重边连成的链。
根据上面的性质我们知道重链的断开点是轻边,一共只有
根据这个性质,对于重链剖分,它能维护很多东西。前提是 dfs 序,在 dfs 时优先访问重儿子能够保证重链 dfs 序连续,然后子树 dfs 序也连续,所以它能配合很多可爱的数据结构进行很多可爱的算法。
针对子树的操作很简单,对于路径操作,我们维护当前点所在的重链顶,然后找两个端点里面深度最深的点往上面跳直到位于同一个重链(具体原因忘了,有博客讲过),过程中根据数据结构更新。
4.长链剖分
类似重链剖分。把子树中深度最大的点作为重儿子。一个点到根节点的重边切换次数是
可以
最大的用处在于优化 某些 dp,但是由于涉及指针,写起来非常难受。
针对链接那道题记录一下一般长剖优化 dp 的做法吧。
快进到
对于节点
-
。 -
。 -
。
注意到其他维度只跟深度有关,可以考虑长剖优化。
对于重儿子发现直接继承祖先的
如果没有
观察转移发现一个点的时间开销是其轻儿子长链长度和,这个东西和空间复杂度基本相同,所以时间均摊下来是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具