支配树 瞎学笔记
支配树上支配集,支配树下我和你。(骗人的,支配树跟支配集毛关系没有)
支配树是用来求解有向图必经点问题的算法。
(u1s1 算法的证明根本不体现支配树的本质,学了也是白学,我是强迫症犯了才补上证明的,不要学我)
基础概念
对于一个有向图,选定 为起点(下文都假定 能到所有点,无自环,不失一般性),对节点 , 支配 当且仅当 是 的必经点,称为 的支配点。不难证明支配关系的自反性、反对称性、传递性。
支配关系还有个类似传递性的神奇性质:若 都支配 ,则 必有支配关系。若不然,任找一条 简单路径,由支配性知 都在上面:若 离 更近,由于 不支配 ,所以可以从 绕过 到 再到 ,与 支配 矛盾; 更近的情况类似。那么易证(读者自证不难):任取一条 简单路径,上面所有 的支配点按离 的距离从近到远排列依次为 ,则对任意 知道 的所有支配点是 。
称 的所有支配点当中除了自己离自己最近的那个为 的最近支配点,记作 , DNE。将所有点 往 连一条边,得到一棵以 为根的内向树。若不然,必定存在大小大于 的环,由传递性可知存在 支配 ,与支配关系的反对称性矛盾。这棵树就是原图的支配树。显然, 的全部支配点就是它在支配树上的全部祖先,并且排列顺序与在原图任意一条 简单路径中离 的距离从近到远的顺序一致。
支配树的求法
显然,若对每个点 都知道了 ,那么支配树自然就求出来了。
外向树
显然,以 为根的外向树的支配树就是自己的反图。
DAG
将 DAG 拓扑排序,那么显然,加入一个点对拓扑序在它之前的点的导出子图的支配树并没有影响。所以考虑按拓扑序依次加入,每次只要考虑当前点的最近支配点是谁,插到树上就可以了。
加入点 的时候,考虑所有边 ,由于是按照拓扑序,所有 在之前已经考虑过了。设 是所有 在支配树上的 LCA,易证有且仅有 的所有支配点是 的所有支配点,即 。
考虑实现。需要实时维护 LCA,考虑树上倍增,每次接一个叶子,确实是可以动态维护倍增数组的,而且很好写,复杂度线对。贴个 P2597 的板子吧。
一般图的 tarjan 算法
一般有向图也是有线对复杂度的求支配树的算法的,叫做 tarjan 算法(Tarjan 老爷子真是 nb,总能发明很难证的算法,而且他自己还总是会证)。虽然 DAG 的特殊求法复杂度跟 tarjan 算法复杂度一样,但是好写的很多,所以 DAG 一般还是写特殊求法。
引入半支配点
找到原图从 出发的一棵 dfs 树(Tarjan 老爷子好像很喜欢 dfs 树耶),不失一般性地,下文认为点 的 dfs 序就是 。对 ,若存在一条 路径满足除端点外全程大于 ,则称 是 的半支配点。
引理:对 , 的任意一条路径都必定经过它们在 dfs 树上的某个公共祖先。证明:设 ,则把 的祖先全删除之后 所在子树就裂开了,前向边和后向边对连通性屁帮助没有,而横叉边只能是大号点到小号点,所以此时 是不能到达 的。
跟据引理,不是 的祖先的节点 一定不是 的半支配点,因为 一定经过小于 的 的祖先(由于 ,所以 不可能是 的后代)。
的所有支配点也一定是 在 dfs 树上的祖先,若不然,删去之后显然可以沿着 dfs 树从 走到 。
所有支配点都是半支配点的祖先。证明:若存在半支配点 是支配点 的祖先,则可以先沿 dfs 树 ,然后从 走一条全程大于 的路径到 ,自然地绕过了 ,与支配性矛盾。
设 的 dfs 序最小的半支配点为最远半支配点,记作 ,亦即在 dfs 树上离 最近的半支配点。我们有 ,知道最远半支配点是对最近支配点的一个良好近似,对求最近支配点有帮助。
最远半支配点的求法
对点 ,枚举所有半支配点到它的路径的一切可能的前驱 :
- 若 则直接用 更新 。正确性显然,充分性的话,由于 ,所以 只能是半支配点到 的路径的端点。
- 若 ,设 ,则用树上路径 (掐头留尾)中所有 的 来更新 。证明:首先 的情况不证自证,下面考虑 的情况。首先想直接用 更新,但它有可能走区间 之间的点 啊,这就没考虑到。若 ,则跟据引理,由 知道一旦走到了 ,就一定要经过 的祖先才能到 ,这是一定小于 的,所以 的半支配点到 的路径上小于 的只能是 (掐头留尾)中所有的 。设从 半支配点走到 的路径上第一次交到这条直链上交的是 ,由于是第一次交上,显然之前走的都大于 ,那自然也大于 ,交上去之后可以直接沿着 dfs 树走到 ,最后走到 。所以这个用所有 的更新方案是既正确又充分的。
通过最远半支配点求最近支配点
对点 ,我们设路径 (留头去尾),(掐头留尾), 是 中最远半支配点最远(亦即 dfs 序最小)的点,显然有 。分成两种情况:
- 若 ,则 。证明:如果 那根据 就显然了,下面考虑 的情况。此时显然对任意 , 不半支配 。假设存在 的不经过 的简单路径,由于 不半支配 ,一定经过小于 的点 。而由于 ,跟据引理 必经过 的祖先。如果祖先为 ,那就对 重新使用上述分析一直到祖先为 为止(一定可实现,因为不能经过 哦)。然后又可以对 重新施加上述分析得到一个新的 ,如此往复得到 。注意到我们考虑的是简单路径, 里所有点迟早都会被得到一遍,就不能继续了,而我们的分析是可以一直持续下去的,矛盾。至此我们知道了 是 的支配点之一,即 ,结合 ,得证。
- 若 ,则 。证明:显然有 ,由 知 。而若 ,此时 一定不支配 (否则 应该调整到 这么近),那么有避开 的路径 ,再沿 dfs 树走到 ,与 支配 矛盾。所以一定有 ,只要证 支配 则有 。
类似上面,假设存在 的不经过 的简单路径。既然不经过 了,那么直链 上面的点都不能经过了,因为一旦交上去便可沿 dfs 树走到 ,绕开了 ,与支配性矛盾。由于 ,所以 以上半支配 的点都不能经过了,剩下来的相当于上面那种情况的局面,可以类似上面无限循环来归谬。
实现
求 的部分,按 dfs 序从后往前更新显然是无后效性的。查询上开下闭的链上最值怎么维护?树剖?可以巧妙地使用带权并查集(Tarjan 又一次使用自己的成果!),每更新完一个点就把它往父亲合并,易证更新到 的时候, 已经合并到了 。并查集只能路径压缩,不能按秩合并,所以复杂度是一个 。
求 的部分恰好也涉及上开下闭的链上最值查询,可以窃取之前的并查集成果。但是查询完之后需要更新的 信息应当是按 dfs 序从前往后更新才是没有后效性的。所以我们可以先把并查集该查的查好存起来(在更新到 的时候恰好是 的可查状态,可以用 vector
记录 todo-list),结束之后再从前往后扫一遍。
注意点: 有可能不能到达所有点,枚举 dfs 序的时候一定是到 nowdfn
instead of n
。初始化的时候应该把所有点的 dfs 序赋为 ,这样在选取「dfs 序最小的半支配点」时比较函数不会出错。
mol ban tea & code.
支配树求必经边
想不到吧,这玩意还能求必经边。
方法是边点转化, 拆成 ,这样若 是支配点,则 是必经边,易证正确性。这时候你不禁想起无向图的两种连通性,边双和点双,边双这么简单,点双这么难,是不是也可以用点边转化将点双转化为边双呢?说的好像有道理,但你给我翻译翻译什么叫 tmd 无向图点边转化?最大流最小割定理证明无向图的点版本门杰定理中提到的点边转化,那也是先变成有向图再点边转化的呀 2333。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
2020-08-25 标记永久化 学会了祭