支配树

为了方便本文的叙述,做出如下可能不严谨的定义:

对于一棵树,我们可以用[x,y]简洁的表示从xy的路径上的所有点组成的集合,假如我们希望这个集合不包含xy,只要将闭区间改为开区间即可。如[x,y)表示从xy的路径上的所有点(不包含y)组成的集合。

我们从一道简单的板子题(在读完这篇文章以后就是了)开始:

给定一个n个点,m条边的有向图G,以及一个出发点r。询问q次,每次给定点xy,保证从r出发可以到达x。问从r出发到达x的所有路径是否都需要经过y

n,m,q105

为了解决这个问题,我们定义有向图上的支配关系:对于一个固定的出发点r,如果从r出发到达x的所有路径都需要经过y,则称yx支配点,即y支配x。特别的,我们认为x不是x的支配点。

我们来研究一下支配关系有哪些性质:

首先,我们将以r为根的dfs树建立出来。容易发现,对于任意一个点x,它的所有支配点只可能是它的祖先——显然,对于不是它的祖先的任意一个点y,我们从r通过树边到达x就不需要经过y

接着我们假设yx的支配点中深度最大的(即距离x最近的),那么还可以发现:对于zyzx的支配点当且仅当zy的支配点。

证明如下:

首先证明充分性。如果y支配xz支配y,那么假设z不支配x,即存在一条路径不经过z。那么显然由于这条路径必定经过y,于是我们就找到了一条不经过z到达y的路径,这与前提条件矛盾,于是假设不成立,充分性得证。

再证明必要性。如果y支配xz不支配y,显然可以找到一条路径不经过z而到达y。此时由于y是深度最大的x的支配点,因此沿着树边一直走到x,必定不会经过z,于是z就不可能是x的支配点。

于是我们就可以知道,对于任意一个点x,我们只要找到它深度最大的支配点y,其余的支配点就都是y的支配点。不难发现,这样的支配关系形成了一个类似树的结构,将之前所说的y当作x的父亲的话,那么x的所有支配点就是这棵树上它的祖先。我们将这棵树叫做支配树,将这样的y记为idom(x)

那么问题来了,如何求出idom(x)呢?

为了解决这个问题,我们先定义一个叫做半支配的东西:

对于任意一个点x,从y出发,只经过不是x的祖先的点就可以到达x(不包含xy),则称yx半支配点,即y半支配x

首先,我们可以发现x的深度最小的半支配点一定是x的祖先。因为假设x的深度最小的半支配点y不是x的祖先,那么显然我们可以沿着树边往回走,一直走到某个x的祖先z上。这其间肯定不会经过除z以外的x的祖先点,于是z的深度比y小,且也是x的半支配点,于是假设不成立,得证。

接着,如果yx的深度最小的半支配点,那么树上路径(x,y)中的点就显然不是x的支配点——因为从y出发存在一条路不经过它们而到达x。我们将这样的y记为sdom(x)

我们来考虑如果求得了半支配点,那么如何求支配点。考虑对于一个点x,树上路径(x,sdom(x))中的点一定不是x的支配点。并且对于任意一个x的祖先y,树上路径(y,sdom(y))中的点也一定不是x的支配点。反之,如果某个x的祖先z不被(x,sdom(x))和任何一个(y,sdom(y))包含,那么z一定是x的支配点——否则一定会存在一条不经过z的路径S到达xS中一定存在两个x的祖先a,b使得树上路径(a,b)经过za,b之间不经过其它x的祖先,于是z一定会被某个区间包含。

于是idom(x)就是不被如上所述的这些区间包含的x的祖先中深度最大的。考虑递归解决这个问题,如果y[x,sdom(x))sdom(y)的深度最小的,那么如果sdom(y)就是sdom(x),显然sdom(x)不会被任何区间包含了,那么idom(x)就是sdom(x)。否则我们就去掉区间(x,sdom(x))并求对于y来说这个问题的答案即可——而这就是idom(y),已经求好了。

好,现在解决最后一个问题,如何求出sdom(x)。分两种情况讨论:

1)最后一条边为前向边或树边。显然另一端就是x的祖先,路径必须结束。这种情况可以直接得到半支配点。

2)最后一条边为横插边或后向边,设走到的点为y,而xydfs树上的lcaz。由于lcaz,因此树上路径[x,z)中的点一定无法到达[y,z)中的点,于是对于[y,z)sdom来说,不会有经过[x,z)中的点的路径,那么显然树上路径[y,z)中的点对于x来说都是合法的。于是用树上路径[y,z)中的点的sdom来更新sdom(x)即可。可以发现沿着时间戳反向求sdom的话,我们求sdom的顺序就不会冲突。

于是我们就解决了文章开头提到的那个问题。至于具体的实现,我们在反向求sdom的过程中可以用带权并查集维护一段树上路径的sdom最小值,在求完一个点的sdom以后将它的儿子与它合并即可。这样每次查询时并查集维护的恰好就是我们需要的那一条链。至于求idom的过程,我们需要知道[x,sdom(x))的信息,于是将请求接入sdom(x)的链表中。每一次求完xsdom后,我们扫描其父亲的请求链表,对于链表中每一个y,可以发现带权并查集此时维护的就是我们要查询的区间[y,sdom(y)),直接从带权并查集上得知sdom最小的为哪一个并存下来并清空链表,在最后求idom时直接用即可。

时间复杂度O((n+m)logn)

有向图上还有类似的支配边的关系,容易发现只有树边能成为支配边。且如果一条边yxx的支配边,需要yx的支配点,且对于所有有非树边指向x的点z,都有x支配z

有向图上还有割点、桥、点双、边双的定义。不过还是下次填坑吧...

参考链接:[https://zhuanlan.zhihu.com/p/30432617][1]