zoukankan      html  css  js  c++  java
  • 有趣的支配树

    别人都在复习$NOIP$,我也不知道干什么,就来学学一些诡异的算法吧...

    首先,假设我们有一张有向图$G(V, E)$,并且选定一个点$s$为根

    我们定义$x$支配$y$,当且仅当从$G$中删除$x$时,没有从$s$到$y$的路径

    为了简便描述,我们找出一棵以$s$为根的$dfs$树$T$

    性质1:易知支配$x$的一定是个集合$S$,并且$S$在$T$中一定都是$x$的祖先

    如果不是,那么至少树边就是一种到$x$的方案

    我们定义$dom(x)$表示支配$x$的点形成的集合

    我们定义$idom(x)$(最近支配点)为$dom(x)$中$dfn$最大的节点,也就是$dom(x)$中离$x$最近的祖先

    性质2:如果我们不断的访问$idom(x), idom(idom(x))...$,那么我们一定能访问完$dom(x)$

    换言之,连边$idom(x) o x$就会构成了一棵树,并且这个树中$x$的所有祖先节点都是支配$x$的点

    证明:我们考虑证明如果$x$支配$u$,并且$y$支配$u$,那么一定有$x$支配$y$或者$y$支配$x$

    由性质1,我们假定$x$是$y$的祖先,如果$x$不支配$y$,那么删除$x$后仍有到$y$的路径,自然也有到$u$的路线了

    这与$x$支配$u$矛盾(链形如:$r o x o y o x o u$)

    我们称这棵树为支配树

    只要考虑求出所有的$idom$,就能求出这棵支配树

    注意到$T$的树边是一个十分强大的限制

    因此,如果$x$存在一条(不经过$x$和$v$之间的树边)到$v$的边,那么$x$的所有子树都不可能支配$v$

    我们取深度最浅的($dfn$最小)的满足条件的$x$

    我们令$x = semi(v)$,称$x$为$v$的半支配点

    注意半支配点不一定是支配点,比如:

    $y$是$x$的半支配点,$r$是$x$的支配点

    我们考虑求出看起来十分有用的半支配点

    对于一个点$x$,有$(y, x)$的前向边的$y$可能成为答案

    不仅如此,如果有$(y, x)$这条返祖边,那么$x o y$的路径中的$semi(i)$都可能成为答案

    同样的道理,$(y, x)$作为交错边时也需要考虑

    考虑以下的定理

    我们令$semi(x)$到$x$路径中的所有点$i$中,$semi(i)$最小的$i$为$y$

    $$idom(x) =
    egin{cases}
    & if ; ; (semi(x) = semi(y)); ; ; semi(x) \
    & else ; ; ; idom(y) \
    end{cases}$$

    证明:

    首先证明第一条

    1. 在删去$semi(x)$后,不存在$s$到$x$的路径

    反证,如果存在这条路径,如果是经过了$y$,那么$semi(y)$会更小,否则$semi(x)$会更小

    2.删去$semi(x)$的任意子树($x$的祖先),都会存在$s$到$x$的路径

    显然,存在一条$semi(x)$不经过树边到$x$的路径,无法断掉

    类似地,证明第二条

    如果懒得画图,那么可以参考路径$s o idom(y) o semi(y) o semi(x) o y o x$

    1.在删去$idom(y)$后,不存在$s$到$x$的路径

    反证,如果存在,如果经过了$y$,那么$idom(y)$不符合条件,如果不经过$y$,那么要么$y$不符合条件,要么$semi(x)$不符合条件

    2.删除$idom(y)$的任意子树($x$的祖先),仍会存在$s$到$x$的路径

    自然的,存在一条到$y$的路径,那么一定可以到达$semi(x)$,也就一定能到达$x$

    现在,我们可以求出$idom(i)$和$semi(i)$了

    我们使用带权并查集维护每个点到当前节点的链的$semi$最小的节点

    按$dfn$倒叙处理(这是为了防止交错边)

    注意并查集合并时,由于取$min$不满足可加可减性,不能使用按秩合并

    复杂度$O(n log n)$

    int n, cnp, tim;
    int f[sid], fa[sid], dfn[sid];
    int idom[sid], semi[sid], ord[sid], mi[sid];
    int cap[sid], q1[sid], q2[sid], nxt[sid * 3], node[sid * 3];
    
    inline void addedge(int *head, int u, int v) {
        nxt[++ cnp] = head[u]; head[u] = cnp; node[cnp] = v;
    }
    
    inline bool cmp(int a, int b) { return dfn[a] < dfn[b]; }
    
    inline int find(int u) {
        if(u == f[u]) return u;
        int v = find(f[u]);
        if(cmp(semi[mi[f[u]]], semi[mi[u]])) mi[u] = mi[f[u]];
        return f[u] = v;
    }
    
    #define cur node[i]
    inline void dfs(int u) {
        dfn[u] = ++ tim; ord[tim] = u;
        for(int i = cap[u]; i; i = nxt[i])
        if(!dfn[cur]) dfs(cur), fa[cur] = u;
    }
    
    inline void tarjan() {
        rep(i, 1, n) 
        idom[i] = semi[i] = mi[i] = f[i] = i;
        
        drep(i, tim, 2) {
            int o = ord[i];
            for(int i = q1[o]; i; i = nxt[i]) if(dfn[cur]) {
           //q1是反向边 find(cur);
    if(cmp(semi[mi[cur]], semi[o])) semi[o] = semi[mi[cur]]; } f[o] = fa[o]; addedge(q2, semi[o], o); for(int i = q2[o]; i; i = nxt[i]) { find(cur); idom[cur] = cmp(semi[mi[cur]], o) ? mi[cur] : o; //idom在这里存的是semi(y) } } rep(i, 2, tim) if(idom[i] != semi[i]) idom[i] = idom[idom[i]]; }

    ps:如果模板错误,请及时提醒我,会速度更正

  • 相关阅读:
    HTMLPARSER.NET 参考资料
    C#线程篇---Task(任务)和线程池不得不说的秘密(5)
    C#控制定位Word光标移动到任意行或者最后一行,取得光标位置等操作
    处理Selection对象和Range对象——Word VBA中重要的两个对象
    C# word开发
    c# 解析JSON的几种办法
    NameValueCollection详解
    解析jquery获取父窗口的元素
    Window_Open详解
    Implementing Remote Validation in MVC
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9763144.html
Copyright © 2011-2022 走看看