支配树(dominator tree)学习笔记

一些定义

  • idom(w)=max{vvw}

​ 记最近支配点 idom(w) iw ,其意义如定义。

  • sdom(w)=min{vv=v0,v1,vk=w使i[1,k)vi>w}

​ 记最远半支配点 sdom(w) sw ,则 sw 的意义是dfs树上 w 的一个“最高分叉点”,也就是最浅的能够从“另一外一条路”绕到 w 的点。(这里我后来想了想感觉这么说也不太对。。。但是演算法笔记里面又是这么说的。。。有点不太懂sdom的意义了。。。可能的确只是一个辅助计算的东西吧。。。)

  • 记图的起点为 r 。接下来讨论的图都是在有向图 G=(V,E) 的dfs树上的,点按照dfs序重标号。
  • u˙v 表示 u v 的祖先, u+v 表示 u˙v $u\neq v$。
  • 路径 P(u,v) 表示沿着树边从 u 走到 v 中间遇到的点的集合(不包括 u,v )。
  • 路径 P[u,v] 表示沿着树边从 u 走到 v 中间遇到的点的集合(包括 u,v )。
  • 路径 P(u,v],P[u,v) 同理。

一些性质

  1. sw+w
    • 首先至少 w 的父亲是一个半支配点,则 sw 不可能是比 faw 大的点。若 sw 不在祖先里,此时有一条 sww 的路径,与dfs树的性质矛盾。
  2. iw˙sw
    • iw 不是 w 的祖先,则可以直接从 r 沿树边到 w 而不用经过 w ;若 iw 不是 sw 祖先,则 sw 处分出至少两条不相交路径,其中 iw 最多只能占一条,因此均矛盾。
  3. iw+w
    • 由定义,显然。
  4. 若对于 v,w v˙w ,则 iwP[v,w] iwP[r,iv]
    • 由定义,存在至少两条 iv v 的不相交路径 P1,P2 ,若 iwP(iv,v) ,则 iw 不能同时位于这两条路径上,矛盾。

两个 idom 的确定定理

  1. 对于 wr ,若 uP(sw,w] 均有 swsu ,则 iw=sw

    • 先说明 sw 支配了 w 。任取一条 r w 的路径 p ,设 x 为路径中最后一个满足 x<sw 的点。如果不存在这样的 x ,也就意味着 sw 一定是路径中的起点,显然有 sw 支配 w 。 接着,令 y p P[sw,w] 中最的第一个点,再取 q={x,v1vk,y} ,那么有 vi>y 。这个考虑反证,若有 vi<y ,注意到在dfs树上一个小点走向大点的路径里一定会经过它们的LCA,取这个LCA为 vj ,因为 x 已经是最后一个 x<sw 的点了,而 vj x 后,因此 vjsw ,又因为 vj y 的祖先,所以有 sw˙vj˙y˙w ,但这样与 y 是最早的 P[sw,w] 中的点矛盾,因此有 vi>y 。这说明 x 可能成为 y 的半支配点,蕴含着 sdom(y)x ,而由假设有 x<sw ,因此 sdom(y)<sdom(w) ,由条件知 y 只能是 sw 。这就说明了任何一条 r w 路径都一定包含了 sw
    • 接下来说明 sw w 最大的支配点。这个由上面的性质2可以立即得出。
  2. 对于 wr ,取 uP(sw,w] sdom 最小的 u ,则 susw iw=iu

    • 我们可以效仿上面的证明,任取一条路径,取第一个 x<iu x ,如果不存在则显然 iu 已经支配了 w ;再取第一个 yP[iu,w] ,注意到这里的条件已经被强化了,所以我们同样可以沿用上面的证明来说明 sdom(y)x 。那么这样就有一个关系图: syx<iususwuw 。但是现在我们还不知道 y 的位置,所以我们要尝试确定它。首先 y 一定不早 P[sw,w] 内,否则这就违反了 su 最小的前提;其次 y 也不会在 P(iu,sw] 内,否则就存在一条 syy 的路径且中间的点都大于 y ,这就避开了 iu 从而能到达 u ,矛盾;又由前提 yP[iu,w] 可得 y=idom(u) 。这样就说明了 idom(u) 一定在 rw 的路径上。所以 idom(w)=idom(u)

      显然这两个定理对于每个 w 都涵盖了所有的情况。

    也就是说,我们先取 P(sw,w] sdom 最小的记为 u ,若 u=w ,则 idom(w)=sdom(w) ,否则 idom(w)=idom(u)


sdom 的确定定理

  • 对于 wr ,有 sdom(w)=min{{v(v,w)Ev<w}{sdom (u)u>w(v,w)使u˙v}}

  • 我们令等式右边为 x ,接下来的证明分成两部分。

  • 先证明 sdom(w)x 。若 x 是在第一种集合里,由定义显然有 swx 。考虑 x 在第二种集合里,则存在点 u>w 使得 sdom(u)=x 且有边 (v,w) 满足u\dot\rightarrow v。那么利用这个条件我们可以构造出一条 x w 的路径,使得路径内经过的点都大于 w ,这说明 x 可能成为 w sdom ,因此也有 sdom(w)x
  • 然后证明 sdom(w)x 。我们取路径 p={sw=v0,v1vk=wv1vk1>w} 。若 k=1 ,显然有 sdom(w)x 成立。否则在这条路径上取最小的一个点使得 vj˙vk1 ,那么一定有 v1vj1>vj ,否则我们取最小的 vi ,其走到 vj 的路径一定会经过 LCA(vi,vj) ,这是一条dfs树上由小指向大的路径,LCA一定不大于 vi ,而由前提可得 LCA 即为 vi ,这导出 vi˙vj ,与前提矛盾,故 v1vj1>vj 。注意到这实际上是构造了一个 vj 满足了第二个集合里面的 u ,那么我们可以得到 sdom(w)sdom(vj)x
  • 结合以上两个不等式,就得到了 x=sdom(w)

sdom idom

定义两个过程:
* link(u,v)
* 将 u 设为森林中 v 的父亲。
* eval(u)
* 如果 u 是森林里的一个根则返回 u ,否则设根为 r ,返回 P(r,u] sdom 最小的点。

利用这两个函数,根据上面的 sdom 确定定理,我们考虑从大到小来求 sdom 。对于扫到的每个 w ,我们计算 sdom(w)=min{sdom(eval(v))(v,e)E} 。考虑这个式子的正确性,当 v<w 时还没扫到 v eval(v) 返回 v ;当 v>w 时,即是对应了 sdom 的式子里的第二个集合里的最小值。计算完 sdom(w) 之后,我们把 w 扔进 sdom(w) 的一个集合里,(Tarjan的论文中)记为 bucket[sdom(w)] 。接着就计算 idom 中的第一种情况,取 bucket[fa(w)] 中的所有点 v ,再取 u=eval(v) ,若 sdom(u)<sdom(v) ,说明此时的 v 不满足第一种情况,但是我们仍然计算出了第二种情况中的 u ,所以先记 idom(v)=u ;否则 idom(v)=fa(w) ,即为第一种情况。这样扫完一遍之后,第二种情况中的 v idom 还没完全求出,只需要顺着再扫一遍所有点直接求出即可。

时间复杂度

link 直接连边 eval 的时候直接用路径压缩并查集的话时间复杂度是 O(mlogn) 的。通过神奇的 link 技巧可以降为 O(mα(n,m)) 但是常数巨大跑起来和一个log差不多。。。带启发式合并的话具体还是看tarjan论文吧。。。

代码实现

变量初值默认为0,图的起点为 1

void dfs(int u) {
    sdom[u] = ++ dfs_clock;
    idx[dfs_clock] = u;
    label[u] = u;
    for (int v: G[u]) {
        if (!sdom[v])
            dfs(v) , fa[v] = u;
        _G[v].pb(u);
    }
}

inline void compress(int u) {
    if (anc[anc[u]]) {
        compress(anc[u]);
        if (sdom[label[anc[u]]] < sdom[label[u]])
            label[u] = label[anc[u]];
        anc[u] = anc[anc[u]];
    }
}

inline int eval(int u) {
    return anc[u] ? (compress(u) , label[u]) : u;
}

inline void link(int p , int u) {
    anc[u] = p;
}

void solve() {
    dfs(1);
    per (i , dfs_clock , 2) {
        int u = idx[i];
        for (int v: _G[u])
            upmin(sdom[u] , sdom[eval(v)]);
        int t = fa[u];
        link(t , u) , bucket[idx[sdom[u]]].pb(u);
        for (int v: bucket[t]) {
            int w = eval(v);
            idom[v] = sdom[w] < sdom[v] ? w : t;
        }
        bucket[t].clear();
    }
    rep (i , 2 , dfs_clock) {
        int u = idx[i];
        if (idom[u] != idx[sdom[u]])
            idom[u] = idom[idom[u]];
    }
}

几个题目

感觉都挺套路/裸的啊。。。不知道有没有啥有意思点的题。。。

  • hdu 4694

    • 直接求dom tree。。
  • Codechef GRAPHCNT

    • 建出dom tree直接扫。。
  • 2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest, Problem L

    • 稍微有一点思考价值的题。。。但是知道这个要用dom tree的话结论是比较显然的。。。

References

其实基本上就是把tarjan的论文翻译了一遍而已hhhhhh
1. THOMAS LENGAUER and ROBERT ENDRE TARJAN ,A Fast Algorithm for Finding Dominators in a Flowgraph .
2. TARJAN, R.E. Applications of path compression on balanced trees.

你可能感兴趣的:(支配树)