一个有源点的有向图,其支配树是满足下面条件的一个有向图:
对于支配树上一点,若断开此点,则源点必定不能到达它的任何儿子,并且能到达其他任意一个点。
不显然的,它是一棵树(当然后面会有证明)
支配树有很多实际用途,我都不知道。
对于一个有向图,假设源点为 r r r,先从 r r r出发构造一棵dfs树。
定义:对于一个点 u u u,若一支配 u u u的点 w w w满足 w ̸ = u w\not= u w̸=u并且 w w w被支配 u u u的其他不含 u u u的支配点支配,则 w w w就是 u u u的最近支配点,记作 i d o m ( u ) idom(u) idom(u)。
通俗的讲, w w w是离 u u u最近的那个支配点,并且能恰好支配 u u u。
Lemma 1: 支配关系不存在环。
Proof: 若 a a a支配 b b b,那么 r r r到 b b b必定经过 a a a,若 b b b支配 a a a则到达 b b b需要经过 a a a,此时并没有经过 b b b,产生矛盾。
Lemma 2: 除源点外,其他点有且仅有一个最近支配点。
Proof: 若 a a a支配 b b b, b b b支配 c c c,则 a a a支配 c c c;若 a a a支配 c c c, b b b支配 c c c,那么 a a a支配 b b b或 b b b支配 a a a,否则可以找到一条路径不经过 a a a而到达 c c c而矛盾。因此支配 u u u的所有点的集合构成了一个全序关系,因此总可以找到一个点满足上述最近支配点的定义。
Theorem 1: 若连接一个点和其最近支配点,那么这张图构成了一棵树,并且满足支配树的定义。
Proof: 由Lemma 1和Lemma 2可以得到这张图就是一棵树。容易证明,若断开 u u u,则源点不可能到达 u u u的任意一个儿子。对于其他点,由支配树的定义和Lemma 2可以推导出这个点不会受到 u u u是否断开的影响。
由Theorem 1,若得到了所有点的 i d o m idom idom,则容易构造出这张图的支配树。
那么怎么求 i d o m idom idom呢?
首先定义:定义一个点 u u u的半支配点 w w w为存在路径 w → u w\rightarrow u w→u,使得除了 w w w,这条路径上任意一个点的dfs序都大于等于 u u u的dfs序,并且 w w w是所有满足条件的点中最小的那个,记作 s d o m ( u ) sdom(u) sdom(u)。
Lemma 3: 对于任意一点 u ̸ = r u\not=r u̸=r, i d o m ( u ) idom(u) idom(u)为 u u u在dfs树上的祖先。
Proof: 若不是祖先,则可以找到一条只经过树边的路径,必定不经过 i d o m ( u ) idom(u) idom(u)。
Lemma 4: 对于任意一点 u ̸ = r u\not=r u̸=r, s d o m ( u ) sdom(u) sdom(u)为 u u u在dfs树上的祖先。
Proof: 若不是祖先,若其dfs序小于 u u u的dfs序,则dfs时必定会经过 s d o m ( u ) sdom(u) sdom(u)而到达 u u u,此时 s d o m ( u ) sdom(u) sdom(u)就是 u u u的祖先,产生矛盾;否则,则可以找到一个点 w w w为 s d o m ( u ) sdom(u) sdom(u)在dfs树上的祖先,路径 w → s d o m ( u ) → u w\rightarrow sdom(u)\rightarrow u w→sdom(u)→u是一条满足定义的路径,并且 w w w的dfs序小于 s d o m ( u ) sdom(u) sdom(u)的dfs序,产生矛盾。
Lemma 5: 对于任意一点 u ̸ = r u\not=r u̸=r, i d o m ( u ) idom(u) idom(u)为 s d o m ( u ) sdom(u) sdom(u)在dfs树上的祖先。
Proof: 若不是祖先,则可以找到一条 r → s d o m ( u ) → u r\rightarrow sdom(u)\rightarrow u r→sdom(u)→u的路径,其中 r → s d o m ( u ) r\rightarrow sdom(u) r→sdom(u)经过dfs树边,显然不经过 i d o m ( u ) idom(u) idom(u); s d o m ( u ) → u sdom(u)\rightarrow u sdom(u)→u这段路径上任意一个点的dfs序大于 u u u,由于Lemma 3,这段路径也不经过 i d o m ( u ) idom(u) idom(u),因此找到了一条路径可以绕过 i d o m ( u ) idom(u) idom(u),产生矛盾。
Lemma 6: 对于任意两点 u ̸ = r , v ̸ = r u\not=r,v\not=r u̸=r,v̸=r,若 u u u是 v v v的祖先,则 u u u是 i d o m ( v ) idom(v) idom(v)的祖先或 i d o m ( v ) idom(v) idom(v)是 i d o m ( u ) idom(u) idom(u)的祖先(上面两种情况都可以相等)。
Proof: 否则 i d o m ( u ) idom(u) idom(u)是 i d o m ( v ) idom(v) idom(v)的祖先, i d o m ( v ) idom(v) idom(v)是 u u u的祖先,那么存在一条路径能绕过 i d o m ( v ) idom(v) idom(v)而到达 u u u进而到达 v v v,产生矛盾。
Theorem 2: 对于任意一点 u ̸ = r u\not=r u̸=r,若 s d o m ( u ) → u sdom(u)\rightarrow u sdom(u)→u只经过树边的路径上,不包括 s d o m ( u ) sdom(u) sdom(u)的任意一点 v v v都满足 s d o m ( u ) sdom(u) sdom(u)是 s d o m ( v ) sdom(v) sdom(v)的祖先或二者相等,则 i d o m ( u ) = s d o m ( u ) idom(u)=sdom(u) idom(u)=sdom(u)。
Proof: 由Lemma 5,若 s d o m ( u ) sdom(u) sdom(u)支配 u u u,则 i d o m ( u ) = s d o m ( u ) idom(u)=sdom(u) idom(u)=sdom(u)。对 r → u r\rightarrow u r→u的任意一条路径,取dfs序最大的点 w w w满足 w w w是 s d o m ( u ) sdom(u) sdom(u)的祖先;取dfs序最小的点 x x x,满足 s d o m ( u ) sdom(u) sdom(u)是 x x x的祖先或二者相等,容易发现这样的点必定存在。那么 s d o m ( x ) sdom(x) sdom(x)的就是 w w w,但是 w w w是 s d o m ( u ) sdom(u) sdom(u)的祖先,因此 x = s d o m ( u ) x=sdom(u) x=sdom(u),那么任何 r → u r\rightarrow u r→u的路径必定经过 s d o m ( u ) sdom(u) sdom(u),因此 s d o m ( u ) sdom(u) sdom(u)支配 u u u。
Theorem 3: 对于任意一点 u ̸ = r u\not=r u̸=r,若 s d o m ( u ) → u sdom(u)\rightarrow u sdom(u)→u只经过树边的路径上,不包括 s d o m ( u ) sdom(u) sdom(u)的点中,对于 s d o m ( v ) sdom(v) sdom(v)的dfs序最小的 v v v,满足 s d o m ( v ) sdom(v) sdom(v)是 s d o m ( u ) sdom(u) sdom(u)的祖先,那么 i d o m ( u ) = i d o m ( v ) idom(u)=idom(v) idom(u)=idom(v)。
Proof: 由Lemma 5和Lemma 6, i d o m ( u ) idom(u) idom(u)是 i d o m ( v ) idom(v) idom(v)的祖先或二者相等。因此只要证明 i d o m ( v ) idom(v) idom(v)支配 u u u即可。类似Theorem 2的证明,取 w w w为 i d o m ( v ) idom(v) idom(v)的祖先, x x x为 i d o m ( v ) idom(v) idom(v)的后代或二者相等,那么 s d o m ( x ) sdom(x) sdom(x)为 w w w,又由于 s d o m ( v ) sdom(v) sdom(v)是最大的,因此 x x x不可能是 s d o m ( u ) sdom(u) sdom(u)的后代;若 x x x是 s d o m ( u ) sdom(u) sdom(u)的祖先或相等,但是是 i d o m ( v ) idom(v) idom(v)的后代,那么就找到了一条绕过 i d o m ( v ) idom(v) idom(v)而到达 v v v的路径。因此 x x x就是 i d o m ( v ) idom(v) idom(v)。那么所有路径都经过 i d o m ( v ) idom(v) idom(v),因此 i d o m ( v ) idom(v) idom(v)支配 u u u。
由Theorem 2和Theorem 3,我们可以轻松的由 s d o m sdom sdom求出 i d o m idom idom了。
Theorem 4: 对于任意一点 u ̸ = r u\not= r u̸=r, s d o m ( u ) sdom(u) sdom(u)是满足下列条件两条件的dfs序最小的 x x x:1. 存在一条边 x → u x\rightarrow u x→u且 x x x的dfs序小于 u u u的dfs序;2. x = s d o m ( v ) x=sdom(v) x=sdom(v), v v v的dfs序大于 u u u的dfs序,并且存在一个点 w w w满足存在一条边 w → u w\rightarrow u w→u且 v v v是 w w w的祖先或相等。
Proof: 显然对于每一个 x x x,都存在一条满足 s d o m sdom sdom要求的路径。由于 s d o m ( u ) sdom(u) sdom(u)后面的点dfs序一定大于等于 u u u,取 s d o m ( u ) sdom(u) sdom(u)的后面一个点 v v v,那么 s d o m ( v ) sdom(v) sdom(v)的dfs序必定等于 s d o m ( u ) sdom(u) sdom(u),并且 v v v符合上述条件。
由Theorem 4可以很方便的求出 s d o m sdom sdom。
以dfs序的倒序枚举每个点,假设有一个数据结构,支持:将一个点作为另外一个点的父亲;查询这个点到根的 s d o m sdom sdom最小值。
设当前枚举的点为 u u u,可以枚举 u u u的前驱 x x x,那么 s d o m ( u ) sdom(u) sdom(u)就是 u u u的前驱在数据结构上的 s d o m sdom sdom最小值的最小值。
对于 u u u的父亲 t t t,每个 s d o m ( w ) = t sdom(w)=t sdom(w)=t并且 w w w是 u u u的后代或二者相等的 w w w在数据结构上的 s d o m sdom sdom最小值就是Theorem 2和Theorem 3描述的最小值,直接更新 w w w的 i d o m idom idom即可。
注意Theorem 3中 v v v的 i d o m idom idom可能还没有被更新,那么暂时令 i d o m ( w ) = v idom(w)=v idom(w)=v,之后若 i d o m ( w ) ̸ = s d o m ( w ) idom(w)\not=sdom(w) idom(w)̸=sdom(w)就更新成 i d o m ( i d o m ( w ) ) idom(idom(w)) idom(idom(w))。
数据结构可以采用带权并查集,时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
//dfn[i]为i的dfs序,idfn[i]是dfs序为i的点,het[i]是i的所有前驱,bkt[i]是所有sdom为i的点
//eval(i)为找到并查集中这个点到父亲的sdom中dfs序最小的那个
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;
}