前言
orz 一下这位大神。
本文献给想要性感地理解支配树的同学,如果你想更性感一点,所有证明均可跳过。
litble 特别菜,有错误请指出,谢谢。
支配点
很久很久以前,有一张有向图,有向图有一个起点 S,有一个叫小 X 的强盗,占据一个点拦路打劫。当小 X 占据了 x点后,若从 S出发就到不了 y点了,那么 x就是 y的支配点。
而支配树,就是满足树上一个点 x的所有祖先都是它的支配点的树。
How to build 支配树
以下我们假定从 S出发可以到达图上所有点。
树形图
显然,树形图自己就是自己的支配树。
DAG
DAG 的话,我们按照拓扑序从小到大进行,假设处理到点 x,则查一遍所有可达点 x的点 y,所有点 y一定被加入了支配树中,那么它们在支配树上的 LCA 就是 x在支配树上的父亲。
倍增就可以做到 O(nlogn),例题洛谷 P2597,代码如下:
一般有向图
一般有向图有一个优秀的做法叫做 Lengauer Tarjan,对,又是 Tarjan,Tarjan tql。
首先,我们从 S开始 dfs 整张图,可以提取出一棵 dfs 树,并且 x的 dfs 序是 dfn(x)。
半支配点
假设存在一个点 y,从 y出发有一条到 x的路径,并且路径上任何一点 z(不包括 x和 y)都满足 dfn(z)>dfn(x),则称 y为 x的半支配点。
记 semi(x)为 x的 dfn 最小的半支配点,因为 x在 dfs 树上的父亲也是它的一个半支配点,所以 semi(x)一定是 x的祖先。
我们为什么需要这个 semi呢?因为我们删掉原图中的非树边后,连边 (semi(x),x),不改变原图中的支配点关系。性感的证明如下:
- 假如在原图上删掉 y,x就不可达了,那么显然 y是 x在 dfs 树上的祖先。
- 假若从 y的某个祖先出发,可以在不经过 y的情况下,走到一个 dfn(y)<dfn(z)≤dfn(x)的点 z,y就是 x的支配点,反之不是。
- 因为不能经过 y,所以从这个祖先走到 z的路径上经过的所有点的 dfn应该大于 y。
- 假如这条路径上的所有点的 dfn都大于 z,则显然通过 (semi(z),z)可以保证新图上这个点依然能到 z。否则,这条路径要么经过一个 dfn小于等于 x大于 y的点(直接满足条件),要么全部经过 dfn大于 x的点(也就是 x的半支配点)
- 所以,新图中的支配点关系与原图相同。
如果求出了 semi,我们就把原图变成了一个 DAG,然后就可以重复 DAG 的做法啦。不过更优的做法也是有的。
求半支配点
对于一个点 x,我们找到所有边 (y,x)对应的 y。
若 dfn(y)<dfn(x)且 dfn(y)比当前找到的 semi(x)的 dfn小,则用 semi(x)=y。
若 dfn(y)>dfn(x),找到树上 y的一个祖先 z,且 dfn(z)>dfn(x),比较 dfn(semi(z))和 dfn(semi(x))的大小,决定是否用 semi(z)更新 semi(x)。
性感的证明就是:
- 考虑从 semi(x)到 x的那条只经过 dfn大于 x的点的路径上,x的前驱。若这个前驱是一个 dfn小于 x的点,那么只有可能从这个点出发是满足条件的。
- 否则,这条路径上可能经过 dfn小于 y且大于 x的点(因为已经证明原图缩成 DAG 合法,所以不可能从 dfn大于 y的点走过来啦 QvQ),枚举这些点 z,它们的 semi就是满足条件的 semi。
从半支配点到支配点
对于 x,我们要求它在支配树上的父亲,也就是 idom(x)。
寻找方法如下:
我们记 P为从 semi(x)到 x的树上路径点集(不包括 semi(x)),而 z是 P中 dfn(semi(z))最小的点。若 semi(z)=semi(x),则有 idom(x)=semi(x),否则有 idom(x)=idom(z)。
对于前半句性感的证明就是,没有 semi(x)的祖先连到 P中的边,则删去 semi(x),x就不可达。
对于后半句性感的证明(见下图)就是:
- 假设删掉 idom(z),x依旧可达,则说明在 dfs 树上,idom(z)有一个祖先,可以走一条非树边(也就是通过 semi 连出来的边,图中红边)到达 x到 idom(z)中间的一个点 k。
- 若 z不是 k的祖先,则删掉 idom(z)后 z仍可达,与支配点定义不符,所以 z是 k的祖先。
- 那么因为 z∈P(我希望你还记得 P的定义),所以 k∈P。因为删除 idom(z)后 semi(z)不可达,所以 dfn(semi(k))≤dfn(idom(z))≤dfn(semi(z)),与我之前定义的 “z是 P中 dfn(semi(z))最小的点” 矛盾,所以该假设不可能成立。
算法流程
那么具体怎么实现呢?其实很简单——用带权并查集!
首先安装 dfs 序从大到小处理,每次处理完毕一个点后,将这个点与它 dfs 树上的父亲在并查集连边。而并查集带的权,就是并查集中这个点到根节点的路径上的所有点,dfn(semi(x))最小的 x是哪个。
找 semi直接找即可,找 idom则在 semi(x)处处理 x的信息即可。
(Tarjan 大神很喜欢 dfs 树和并查集啊)
例题:HDU4694(起点为 n,求每个点支配的点的编号和)
Wraning: 数据出错,对于 n无法到的点,答案为 0,并且清空边集的时候,与 0 相连的边集也要清空(MDZZ 调了劳资一下午)
5 条评论
孤月 · 2020年6月14日 4:58 下午
2020 年蒟蒻前来% 神仙,非常感谢这篇 blog。
XZYQvQ · 2018年10月13日 11:01 上午
性感 KB,在线支配,给您不一样的被吊打体验B_Z_B_Y · 2018年10月13日 8:22 上午
233333333333
boshi · 2018年10月12日 8:59 下午
第三句话存在严重错误,请稍加斟酌
litble · 2018年10月12日 9:26 下午
第三句话是
怎么了?你觉得你自己不够性感?