伪目录
- 给出支配树的定义
- 给出一些性质
- 介绍快速构造支配树的Lengauer-Tarjan算法及具体实现
支配树是啥
一个有源点的有向图,其支配树是知足下面条件的一个有向图:html
对于支配树上一点,若断开此点,则源点一定不能到达它的任何儿子,而且能到达其余任意一个点。web
不显然的,它是一棵树(固然后面会有证实)算法
支配树有不少实际用途,我都不知道。数据结构
一些性质
对于一个有向图,假设源点为
r,先从
r出发构造一棵dfs树。app
定义:对于一个点
u,若一支配
u的点
w知足
w̸=u而且
w被支配
u的其余不含
u的支配点支配,则
w就是
u的最近支配点,记做
idom(u)。dom
通俗的讲,
w是离
u最近的那个支配点,而且能刚好支配
u。svg
Lemma 1: 支配关系不存在环。spa
Proof: 若
a支配
b,那么
r到
b一定通过
a,若
b支配
a则到达
b须要通过
a,此时并无通过
b,产生矛盾。code
Lemma 2: 除源点外,其余点有且仅有一个最近支配点。xml
Proof: 若
a支配
b,
b支配
c,则
a支配
c;若
a支配
c,
b支配
c,那么
a支配
b或
b支配
a,不然能够找到一条路径不通过
a而到达
c而矛盾。所以支配
u的全部点的集合构成了一个全序关系,所以总能够找到一个点知足上述最近支配点的定义。
Theorem 1: 若链接一个点和其最近支配点,那么这张图构成了一棵树,而且知足支配树的定义。
Proof: 由Lemma 1和Lemma 2能够获得这张图就是一棵树。容易证实,若断开
u,则源点不可能到达
u的任意一个儿子。对于其余点,由支配树的定义和Lemma 2能够推导出这个点不会受到
u是否断开的影响。
由Theorem 1,若获得了全部点的
idom,则容易构造出这张图的支配树。
那么怎么求
idom呢?
首先定义:定义一个点
u的半支配点
w为存在路径
w→u,使得除了
w,这条路径上任意一个点的dfs序都大于等于
u的dfs序,而且
w是全部知足条件的点中最小的那个,记做
sdom(u)。
Lemma 3: 对于任意一点
u̸=r,
idom(u)为
u在dfs树上的祖先。
Proof: 若不是祖先,则能够找到一条只通过树边的路径,一定不通过
idom(u)。
Lemma 4: 对于任意一点
u̸=r,
sdom(u)为
u在dfs树上的祖先。
Proof: 若不是祖先,若其dfs序小于
u的dfs序,则dfs时一定会通过
sdom(u)而到达
u,此时
sdom(u)就是
u的祖先,产生矛盾;不然,则能够找到一个点
w为
sdom(u)在dfs树上的祖先,路径
w→sdom(u)→u是一条知足定义的路径,而且
w的dfs序小于
sdom(u)的dfs序,产生矛盾。
Lemma 5: 对于任意一点
u̸=r,
idom(u)为
sdom(u)在dfs树上的祖先。
Proof: 若不是祖先,则能够找到一条
r→sdom(u)→u的路径,其中
r→sdom(u)通过dfs树边,显然不通过
idom(u);
sdom(u)→u这段路径上任意一个点的dfs序大于
u,因为Lemma 3,这段路径也不通过
idom(u),所以找到了一条路径能够绕过
idom(u),产生矛盾。
Lemma 6: 对于任意两点
u̸=r,v̸=r,若
u是
v的祖先,则
u是
idom(v)的祖先或
idom(v)是
idom(u)的祖先(上面两种状况均可以相等)。
Proof: 不然
idom(u)是
idom(v)的祖先,
idom(v)是
u的祖先,那么存在一条路径能绕过
idom(v)而到达
u进而到达
v,产生矛盾。
Theorem 2: 对于任意一点
u̸=r,若
sdom(u)→u只通过树边的路径上,不包括
sdom(u)的任意一点
v都知足
sdom(u)是
sdom(v)的祖先或两者相等,则
idom(u)=sdom(u)。
Proof: 由Lemma 5,若
sdom(u)支配
u,则
idom(u)=sdom(u)。对
r→u的任意一条路径,取dfs序最大的点
w知足
w是
sdom(u)的祖先;取dfs序最小的点
x,知足
sdom(u)是
x的祖先或两者相等,容易发现这样的点一定存在。那么
sdom(x)的就是
w,可是
w是
sdom(u)的祖先,所以
x=sdom(u),那么任何
r→u的路径一定通过
sdom(u),所以
sdom(u)支配
u。
Theorem 3: 对于任意一点
u̸=r,若
sdom(u)→u只通过树边的路径上,不包括
sdom(u)的点中,对于
sdom(v)的dfs序最小的
v,知足
sdom(v)是
sdom(u)的祖先,那么
idom(u)=idom(v)。
Proof: 由Lemma 5和Lemma 6,
idom(u)是
idom(v)的祖先或两者相等。所以只要证实
idom(v)支配
u便可。相似Theorem 2的证实,取
w为
idom(v)的祖先,
x为
idom(v)的后代或两者相等,那么
sdom(x)为
w,又因为
sdom(v)是最大的,所以
x不多是
sdom(u)的后代;若
x是
sdom(u)的祖先或相等,可是是
idom(v)的后代,那么就找到了一条绕过
idom(v)而到达
v的路径。所以
x就是
idom(v)。那么全部路径都通过
idom(v),所以
idom(v)支配
u。
由Theorem 2和Theorem 3,咱们能够轻松的由
sdom求出
idom了。
Theorem 4: 对于任意一点
u̸=r,
sdom(u)是知足下列条件两条件的dfs序最小的
x:1. 存在一条边
x→u且
x的dfs序小于
u的dfs序;2.
x=sdom(v),
v的dfs序大于
u的dfs序,而且存在一个点
w知足存在一条边
w→u且
v是
w的祖先或相等。
Proof: 显然对于每个
x,都存在一条知足
sdom要求的路径。因为
sdom(u)后面的点dfs序必定大于等于
u,取
sdom(u)的后面一个点
v,那么
sdom(v)的dfs序一定等于
sdom(u),而且
v符合上述条件。
由Theorem 4能够很方便的求出
sdom。
具体实现
以dfs序的倒序枚举每一个点,假设有一个数据结构,支持:将一个点做为另一个点的父亲;查询这个点到根的
sdom最小值。
设当前枚举的点为
u,能够枚举
u的前驱
x,那么
sdom(u)就是
u的前驱在数据结构上的
sdom最小值的最小值。
对于
u的父亲
t,每一个
sdom(w)=t而且
w是
u的后代或两者相等的
w在数据结构上的
sdom最小值就是Theorem 2和Theorem 3描述的最小值,直接更新
w的
idom便可。
注意Theorem 3中
v的
idom可能尚未被更新,那么暂时令
idom(w)=v,以后若
idom(w)̸=sdom(w)就更新成
idom(idom(w))。
数据结构能够采用带权并查集,时间复杂度
O(nlogn)
代码
int getidom()
{
for(int i=cnt; i>1; --i)
{
int u=idfn[i];
for(int v:het[u])
{
if(!dfn[v])
{
continue;
}
int w=eval(v);
if(dfn[sdom[w]]<dfn[sdom[u]])
{
sdom[u]=sdom[w];
}
}
bkt[sdom[u]].push_back(u);
int t=fa[u];
dsu::fa[u]=t;
for(int v:bkt[t])
{
int w=eval(v);
idom[v]=(sdom[w]==sdom[v])?t:w;
}
bkt[t].clear();
}
for(int i=2; i<=cnt; ++i)
{
int u=idfn[i];
idom[u]=(idom[u]==sdom[u])?(idom[u]):(idom[idom[u]]);
}
return 0;
}