图论进阶总结 【第二部分 树上问题】
图论进阶总结 【第二部分 树上问题】
1.树的直径
定义:树上两个最远的点之间的路径(或距离)。
当然,当我们关注一个概念的时候,里面的字眼当然是很重要的。就比如”最长“,这说明直径的最长性,这个性质就有可能在许多证明里运用。
怎么求呢?
-
树形DP
-
两次DFS(不使用于含负权的图)
这个两次DFS就比较巧了,其实它就是使用了直径的最长性进行证明。
2.最近公共祖先
直观地理解,最近公共祖先LCA就是从这两个点向上走到的第一个点,再往后直到根节点的链上的节点都是公共祖先了
LCA(x,y)沟通了x,y与根节点,也是path(x,y)上的一个重要的划分点。
同时,求解LCA时用到的树上倍增技巧也是很常见的,这并不只能用来求LCA,还可以作为倍增优化树上DP的预处理
而倍增的Tarjan算法就不是很常用了。其本质就是使用并查集来快速找到祖先节点,是对朴素标记法的优化。
对比
方法 | 时间复杂度 | 思想 | 优点 | 缺点 |
---|---|---|---|---|
向上标记法 | 暴力 | 实现简单 | 慢 | |
树上倍增法 | 倍增 | 思想容易理解/实现比较简单 | 速度中等 | |
LCA的Tarjan算法 | 并查集优化暴力 | 比较快 | 离线 |
2.1 树上差分
类比序列上的差分,树上差分就是处理路径信息的。
其基础思想就是路径操作转单点操作,然后最后累积影响,求出子树和。
LCA在这其中是起到一个对路径印象的限制与消除的作用的。
至于点差分、边差分,以及他们实现上的区别略。有些比较广义的树上差分见下。
3 基环树
基环树就是含有N个点N条边的无向连通图。所以这是一棵被添了一条边的树。
其中有一点比较重要的性质:
-
每个点有且仅有一条出边的有向图是内向树
-
每个点有且仅有一条入边的有向图是外向树
这两个描述是我们确定有向图中基环树的关键。然后我们一旦确定基环树,就可以使用这两个充要条件进行解决。
这些树结构都比树要复杂,通常方法就是将他们拆成环和树来分别处理。
同时,如果有些题目含有动态规划的,我们也可以像处理环形DP一样断开环把它转化为树,然后再强制使用断开时忽略的情况计算。
4 例题
要怎么合并两个连通块的直径使得其最小呢?
首先维护连通性可考虑并查集,但是并查集又怎么合并直径呢。
考虑分类讨论选择的合并点的位置,并证明几种选择之间的大小关系,利用直径的最长性。
然后就发现选择直径中点是最好的,即
中间证明太多就不写了。只是说明树的直径常常是分类讨论/贪心中的关键点,这样还可以利用直径的最长性进行证明。
本题求一个树中的一个子树,要求其他所有点到达它的最大值最小。
如果问题复杂,不妨先研究小规模问题。基于这样的思路,我们考虑只选一个点的最优方案。这种问题的突破常常是直径,研究直径中点后发现,这个最大值不会小于直径的二分之一,最小值在直径中点取得。推广至k>1,将无根树化为以直径中点为根的树,同样必选直径中点。请读者考虑证明取非直径中点开始时的最大值的最大值必大于二分之一直径,而在这种开局下,取剩下k-1个点带来的答案优化都是一样的,最后取直径中点在全局也是最优的。
所以写这个题只是说有这样一种渐进思考的方法,然后推广看是否还是最优的。
这是一个路径问题,但是不像雨天的尾巴那么明显的一个树上差分
但是如之前我们说的一样,应该将问题尽可能化为精准的数学形式。这个时候就发现我们需要路径长度了,并且这个问题有这样的形式:depth[S]-depth[x]=W[x]
移项过后一边与x有关一边是定值。那么就可以转化为树上差分的基本问题——路径覆盖。
本题不能再使用线段树合并计算,也不能对于每一个点开一个计数数组。
但是因为这次求解的和满足区间可减,所以可以只拿一个数组计数,计算加子树之后和加子树之前的差即可。
首先要注意到每条边的权值相等,这样只要我们不走重复的路就好,想到LCA可以划分路径
画画图可以模到一个结论,三个点中LCA一定有2个相等,如果要到相等的LCA集合,肯定有两个人都会重复走一段路,不优。选那个不相同的即可
首先我们有了猜想之后可以模拟看结论,然后再试着证明,LCA的证明经常是分类讨论子树位置,这个结论也不例外。
给生成树上加一条非树边就能变成一个环,将原来的点用非树边替换,这样就可以使得边权变大。这种变换是求特别的生成树时常见的。
然后考虑怎么样才能快速求一条路径上面的最大/次大边权。处理可以拼接的路径信息,可以树上倍增进行优化。
深度优先遍历一个基环树有什么样的特征吗?会发现去除环之后的森林是肯定会遍历的,环上一旦按某个方向遍历,就只有一条边不会被遍历,即入环后按反方向走到的第一条边。
所以作为树和环的结合体,通常都要把树和环拆开考虑
图是一个基环树森林的形式。根据题目,你一旦离开某一基环树,就不能再返回,无论什么方法。同时,你也不能在一棵基环树里面坐渡船到达另一个在同一个基环树里的点。这些意味着你一旦在某一棵基环树走到无路可走,就必须乘船离开到另一棵基环树。
所以每次在基环树上走,一定要走他的最长链,或说直径。
考虑基环树上直径的组分,就是某两棵树的树根能向里走的最长距离加在环上树根之间的路径。先处理出前部分,然后断环成链DP
将限制关系化为连边。然后断掉环上的一条边就能将它化为树形DP
本文来自博客园,作者:haozexu,转载请注明原文链接:https://www.cnblogs.com/haozexu/p/18281761
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~