支配树与Lengauer-Tarjan算法

伪目录

  1. 给出支配树的定义
  2. 给出一些性质
  3. 介绍快速构造支配树的Lengauer-Tarjan算法及具体实现

支配树是啥

一个有源点的有向图,其支配树是知足下面条件的一个有向图:html

对于支配树上一点,若断开此点,则源点一定不能到达它的任何儿子,而且能到达其余任意一个点。web

不显然的,它是一棵树(固然后面会有证实)算法

支配树有不少实际用途,我都不知道数据结构

一些性质

对于一个有向图,假设源点为 r r ,先从 r r 出发构造一棵dfs树。app

定义:对于一个点 u u ,若一支配 u u 的点 w w 知足 w ̸ = u w\not= u 而且 w w 被支配 u u 的其余不含 u u 的支配点支配,则 w w 就是 u u 的最近支配点,记做 i d o m ( u ) idom(u) dom

通俗的讲, w w 是离 u u 最近的那个支配点,而且能刚好支配 u u svg

Lemma 1: 支配关系不存在环。spa

Proof: 若 a a 支配 b b ,那么 r r b b 一定通过 a a ,若 b b 支配 a a 则到达 b b 须要通过 a a ,此时并无通过 b b ,产生矛盾。code

Lemma 2: 除源点外,其余点有且仅有一个最近支配点。xml

Proof: 若 a a 支配 b b b b 支配 c c ,则 a a 支配 c c ;若 a a 支配 c c b b 支配 c c ,那么 a a 支配 b b b b 支配 a a ,不然能够找到一条路径不通过 a a 而到达 c c 而矛盾。所以支配 u u 的全部点的集合构成了一个全序关系,所以总能够找到一个点知足上述最近支配点的定义。

Theorem 1: 若链接一个点和其最近支配点,那么这张图构成了一棵树,而且知足支配树的定义。

Proof: 由Lemma 1和Lemma 2能够获得这张图就是一棵树。容易证实,若断开 u u ,则源点不可能到达 u u 的任意一个儿子。对于其余点,由支配树的定义和Lemma 2能够推导出这个点不会受到 u u 是否断开的影响。

由Theorem 1,若获得了全部点的 i d o m idom ,则容易构造出这张图的支配树。

那么怎么求 i d o m idom 呢?

首先定义:定义一个点 u u 的半支配点 w w 为存在路径 w u w\rightarrow u ,使得除了 w w ,这条路径上任意一个点的dfs序都大于等于 u u 的dfs序,而且 w w 是全部知足条件的点中最小的那个,记做 s d o m ( u ) sdom(u)

Lemma 3: 对于任意一点 u ̸ = r u\not=r i d o m ( u ) idom(u) u u 在dfs树上的祖先。

Proof: 若不是祖先,则能够找到一条只通过树边的路径,一定不通过 i d o m ( u ) idom(u)

Lemma 4: 对于任意一点 u ̸ = r u\not=r s d o m ( u ) sdom(u) u u 在dfs树上的祖先。

Proof: 若不是祖先,若其dfs序小于 u u 的dfs序,则dfs时一定会通过 s d o m ( u ) sdom(u) 而到达 u u ,此时 s d o m ( u ) sdom(u) 就是 u u 的祖先,产生矛盾;不然,则能够找到一个点 w w s d o m ( u ) sdom(u) 在dfs树上的祖先,路径 w s d o m ( u ) u w\rightarrow sdom(u)\rightarrow u 是一条知足定义的路径,而且 w w 的dfs序小于 s d o m ( u ) sdom(u) 的dfs序,产生矛盾。

Lemma 5: 对于任意一点 u ̸ = r u\not=r i d o m ( u ) idom(u) s d o m ( u ) sdom(u) 在dfs树上的祖先。

Proof: 若不是祖先,则能够找到一条 r s d o m ( u ) u r\rightarrow sdom(u)\rightarrow u 的路径,其中 r s d o m ( u ) r\rightarrow sdom(u) 通过dfs树边,显然不通过 i d o m ( u ) idom(u) s d o m ( u ) u sdom(u)\rightarrow u 这段路径上任意一个点的dfs序大于 u u ,因为Lemma 3,这段路径也不通过 i d o m ( u ) idom(u) ,所以找到了一条路径能够绕过 i d o m ( u ) idom(u) ,产生矛盾。

Lemma 6: 对于任意两点 u ̸ = r , v ̸ = r u\not=r,v\not=r ,若 u u v v 的祖先,则 u u i d o m ( v ) idom(v) 的祖先或 i d o m ( v ) idom(v) i d o m ( u ) idom(u) 的祖先(上面两种状况均可以相等)。

Proof: 不然 i d o m ( u ) idom(u) i d o m ( v ) idom(v) 的祖先, i d o m ( v ) idom(v) u u 的祖先,那么存在一条路径能绕过 i d o m ( v ) idom(v) 而到达 u u 进而到达 v v ,产生矛盾。

Theorem 2: 对于任意一点 u ̸ = r u\not=r ,若 s d o m ( u ) u sdom(u)\rightarrow u 只通过树边的路径上,不包括 s d o m ( u ) sdom(u) 的任意一点 v v 都知足 s d o m ( u ) sdom(u) s d o m ( v ) sdom(v) 的祖先或两者相等,则 i d o m ( u ) = s d o m ( u ) idom(u)=sdom(u)

Proof: 由Lemma 5,若 s d o m ( u ) sdom(u) 支配 u u ,则 i d o m ( u ) = s d o m ( u ) idom(u)=sdom(u) 。对 r u r\rightarrow u 的任意一条路径,取dfs序最大的点 w w 知足 w w s d o m ( u ) sdom(u) 的祖先;取dfs序最小的点 x x ,知足 s d o m ( u ) sdom(u) x x 的祖先或两者相等,容易发现这样的点一定存在。那么 s d o m ( x ) sdom(x) 的就是 w w ,可是 w w s d o m ( u ) sdom(u) 的祖先,所以 x = s d o m ( u ) x=sdom(u) ,那么任何 r u r\rightarrow u 的路径一定通过 s d o m ( u ) sdom(u) ,所以 s d o m ( u ) sdom(u) 支配 u u

Theorem 3: 对于任意一点 u ̸ = r u\not=r ,若 s d o m ( u ) u sdom(u)\rightarrow u 只通过树边的路径上,不包括 s d o m ( u ) sdom(u) 的点中,对于 s d o m ( v ) sdom(v) 的dfs序最小的 v v ,知足 s d o m ( v ) sdom(v) s d o m ( u ) sdom(u) 的祖先,那么 i d o m ( u ) = i d o m ( v ) idom(u)=idom(v)

Proof: 由Lemma 5和Lemma 6, i d o m ( u ) idom(u) i d o m ( v ) idom(v) 的祖先或两者相等。所以只要证实 i d o m ( v ) idom(v) 支配 u u 便可。相似Theorem 2的证实,取 w w i d o m ( v ) idom(v) 的祖先, x x i d o m ( v ) idom(v) 的后代或两者相等,那么 s d o m ( x ) sdom(x) w w ,又因为 s d o m ( v ) sdom(v) 是最大的,所以 x x 不多是 s d o m ( u ) sdom(u) 的后代;若 x x s d o m ( u ) sdom(u) 的祖先或相等,可是是 i d o m ( v ) idom(v) 的后代,那么就找到了一条绕过 i d o m ( v ) idom(v) 而到达 v v 的路径。所以 x x 就是 i d o m ( v ) idom(v) 。那么全部路径都通过 i d o m ( v ) idom(v) ,所以 i d o m ( v ) idom(v) 支配 u u

由Theorem 2和Theorem 3,咱们能够轻松的由 s d o m sdom 求出 i d o m idom 了。

Theorem 4: 对于任意一点 u ̸ = r u\not= r s d o m ( u ) sdom(u) 是知足下列条件两条件的dfs序最小的 x x :1. 存在一条边 x u x\rightarrow u x x 的dfs序小于 u u 的dfs序;2. x = s d o m ( v ) x=sdom(v) v v 的dfs序大于 u u 的dfs序,而且存在一个点 w w 知足存在一条边 w u w\rightarrow u v v w w 的祖先或相等。

Proof: 显然对于每个 x x ,都存在一条知足 s d o m sdom 要求的路径。因为 s d o m ( u ) sdom(u) 后面的点dfs序必定大于等于 u u ,取 s d o m ( u ) sdom(u) 的后面一个点 v v ,那么 s d o m ( v ) sdom(v) 的dfs序一定等于 s d o m ( u ) sdom(u) ,而且 v v 符合上述条件。

由Theorem 4能够很方便的求出 s d o m sdom

具体实现

以dfs序的倒序枚举每一个点,假设有一个数据结构,支持:将一个点做为另一个点的父亲;查询这个点到根的 s d o m sdom 最小值。

设当前枚举的点为 u u ,能够枚举 u u 的前驱 x x ,那么 s d o m ( u ) sdom(u) 就是 u u 的前驱在数据结构上的 s d o m sdom 最小值的最小值。

对于 u u 的父亲 t t ,每一个 s d o m ( w ) = t sdom(w)=t 而且 w w u u 的后代或两者相等的 w w 在数据结构上的 s d o m sdom 最小值就是Theorem 2和Theorem 3描述的最小值,直接更新 w w i d o m idom 便可。

注意Theorem 3中 v v i d o m idom 可能尚未被更新,那么暂时令 i d o m ( w ) = v idom(w)=v ,以后若 i d o m ( w ) ̸ = s d o m ( w ) idom(w)\not=sdom(w) 就更新成 i d o m ( i d o m ( w ) ) idom(idom(w))

数据结构能够采用带权并查集,时间复杂度 O ( n log n ) O(n\log n)

代码

//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;
}