• 必经点树


    http://sujinyue.is-programmer.com/posts/45318.html

    定义x的半必经点为某个x在DFS树上的祖先y,且保证在y---x路径上删除除端点外的任意一点后仍然存在路径从y到x,令semi(x)为所有y中dfn最小的

    考虑半必经点定理:

    对于一点y,x∈pre(y):

    ①dfn[x]<dfn[y],x即为y在DFS树上的祖先,根据定义:if(dfn[x]<dfn[semi[y]])semi[y]=x;

    ②dfn[x]>dfn[y],x不为y的祖先,此时对于任意x的祖先z,满足dfn[z]>dfn[y]:if(dfn[semi[z]]<dfn[semi[y]])semi[y]=semi[z]

    这里有几个地方需要解释一下

    一、为什么要dfn[z]>dfn[y]:考虑u=lca(x,y),x所属的是一个较晚被dfs到的子树,如果某个z是x的祖先,且dfn[z]<dfn[y],那么此时z必为y在DFS树上的祖先,那么直接将z删去便可使semi(z)无法到达y,与定义不符

    二、这样子获得的semi[y]一定为y的祖先么:x所属的子树较晚被dfs到,故获得的semi必为y的祖先

    必经点定理相当直观,不叙述

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define NN 100001
    #define MM 1000000
    struct chain
    {
        int ver[NN],next[MM<<1],to[MM<<1],tot;bool f[MM<<1];
        void addedge(int from,int t,bool v)
        {next[++tot]=ver[from];to[tot]=t;f[tot]=v;ver[from]=tot;}
    }G,dom;
    int dfn[NN],clk,idom[NN],semi[NN],fa[NN],id[NN];
    struct Ufs
    {
        int p[NN],best[NN];
        int getf(int x)
        {
            if(x==p[x])return x;
            int t=getf(p[x]);
            if(dfn[semi[best[x]]]>dfn[semi[best[p[x]]]])best[x]=best[p[x]];
            p[x]=t;
            return p[x];
        }
        int getbest(int x)
        {getf(x);return best[x];}
    }ufs;
    int n,m;
    void dfs(int o)
    {
        dfn[o]=++clk;id[clk]=o;
        for(int i=G.ver[o];i;i=G.next[i])
            if(!dfn[G.to[i]]&&G.f[i])
            {fa[G.to[i]]=o;dfs(G.to[i]);}
    }
    bool flag[NN];
    void read(int& a)
    {
        static char t;
        t=getchar();a=0;
        while(t<'0'||t>'9'){t=getchar();}
        while(t>='0'&&t<='9')
        {a=a*10+(t-'0');t=getchar();}
    }
    int main()
    {
    //  scanf("%d%d",&n,&m);
        read(n);read(m);
        for(int i=1;i<=m;i++)
        {
            int a,b;//scanf("%d%d",&a,&b);
            read(a);read(b);
            G.addedge(a,b,1);
            G.addedge(b,a,0);
        }
        dfs(1);
        for(int i=1;i<=n;i++)ufs.p[i]=i,ufs.best[i]=i,semi[i]=i;
        for(int i=n;i>1;i--)
        {
            int tmp=2100000000;
            for(int t=G.ver[id[i]];t;t=G.next[t])
            {
                if(G.f[t])continue;
                if(dfn[semi[ufs.getbest(G.to[t])]]<tmp)
                {
                    tmp=dfn[semi[ufs.getbest(G.to[t])]];
                }
            }
            semi[id[i]]=id[tmp];
            dom.addedge(semi[id[i]],id[i],1);
            for(int t=dom.ver[fa[id[i]]];t;t=dom.next[t])
            {
                if(dfn[semi[ufs.getbest(dom.to[t])]]<dfn[fa[id[i]]])
                    idom[dom.to[t]]=ufs.getbest(dom.to[t]);
                else idom[dom.to[t]]=semi[dom.to[t]];
            }
            dom.ver[fa[id[i]]]=0;
            ufs.p[id[i]]=fa[id[i]];
        }
        semi[1]=1;idom[1]=0;
        for(int i=2;i<=n;i++)
            if(idom[id[i]]!=semi[id[i]])
                idom[id[i]]=idom[idom[id[i]]];
        int ans=0;
        for(int i=2;i<=n;i++)
            if(!flag[idom[i]]){++ans;flag[idom[i]]=true;}
         
        printf("%d
    ",ans);
        for(int i=1;i<=n;i++)
            if(flag[i])
            {
                ans--;
                if(ans==0)printf("%d
    ",i);
                else printf("%d ",i);
            }
    }
    

      

  • 相关阅读:
    如何实现LRU缓存淘汰算法
    排序算法(上)
    MySQL为什么有时候会选错索引?
    mysql开启慢查询——wamp
    普通索引和唯一索引,应该如何选择
    php开发常用插件
    mysql批量添加大量测试数据
    .text()设置文本,.html()设置html, .val()设置值的使用
    ajax .load()方法
    jquery学习笔记一之window.onload与$(document).ready()区别
  • 原文地址:https://www.cnblogs.com/cutemush/p/12694515.html
Copyright © 2020-2023  润新知