• Blockade(tarjan求割点...)-poi2008


    Blockade(tarjan求割点...)-poi2008

    题意:n个点,m条边双向连通,无重边,自环;输出n个数,代表把第i个点去掉后,有多少访问不能发生a->b ≠b->a;

    解:对于一个点有两种情况:

    1,非割点:结果(n-1)*2,这个点不能到别的店,别的点也不能到这个点;

    2,割点。

    判断一个点是否为割点

    1,对于根节点,计算其子树数量,如果有两颗以上的子树,就是割点,去掉这个点,两颗子树不会互达;

    2,对于非根节点,tarjan求。维护两个数组dfn[],low[],dfn[u]时间戳,low[u]顶点u及其子树中的点,通过非父子边,能够回溯到的最早的点(dfn最小)。

    对于边(u,v),如果dfn【u】<=low【v】,u就是割点,其他类似tarjan求连通分量

    割点状况:

    1》,以u为根的子树对外界的来往

    设子树数量为ss,对外界n-1+n-1

    2》,外界对以u为根子树的来往

    (n-1-ss)*(ss+1)其他点到这颗子树上的点

    即:ans【u】+=(n-1-ss)*(ss+1)+(n-1)

     

     

     

    /*size[u]表示以u为根的子树有多少节点

    isok[u],判断u是否为割点*/

    vector存图会超内存,用链式前向星存图

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    const int mod=142857;
    const int inf=0x3f3f3f3f;
    typedef long long ll;
    typedef pair<int,int> pii;
    const int N=5e5+10;
    
    int n,m;
    struct edge { 
        int v , next ;
    }e[N<<1] ; 
    int tot,last[N] ;
    inline void add(int u,int v) 
    {
        e[++tot]=(edge){v,last[u]};
        last[u]=tot ;
        e[++tot]=(edge){u,last[v]};
        last[v]=tot ;
    }
    ll ans[maxn];
    
    int idx,dfn[maxn],low[maxn];
    int size[maxn];
    bool isok[maxn];
    
    void tarjan(int u)
    {
        dfn[u]=low[u]=++idx;
        size[u]=1;
        int cnt=0,ss=0;
        for ( int i = last[u] ; i != -1 ; i = e[i].next ) {
            int v = e[i].v ;
            if (!dfn[v]) {
                tarjan( v ) ; 
                size[u] += size[v] ;
                low[u] = min ( low[u] , low[v] ) ;
                if ( dfn[u] <= low[v] ) {
                    cnt ++ ; 
                    ss += size[v] ;
                    ans[u] += (ll)size[v] * ( n - size[v] ) ;
                    if ( u != 1 || cnt > 1 ) 
                        isok[u] = 1 ;
                }        
            }
            else low[u] = min ( low[u] , dfn[v] ) ;
        }
        if(!isok[u]) ans[u]=(n-1)*2;
        else ans[u]+= (ll)(n-ss-1)*(ss+1)+(n-1);
    }
    int main()
    {
        while(cin>>n>>m)
        {
            memset(last,-1,sizeof(last));
            memset(isok,0,sizeof(isok));
            for(int i=1; i<=n; i++)
              dfn[i]=low[i]=0;
            tot=idx=0;
            for(int i=1; i<=m; i++)
            {
                int u,v;
                cin>>u>>v;
                add(u,v);
            }
            tarjan(1);
            for(int i=1; i<=n; i++)
             printf("%lld
    ",ans[i]);
        }
    }
  • 相关阅读:
    centos7下配置时间同步服务器
    交换机简单配置(转)
    ubuntu16.04安装docker CE
    docker下使用DB2
    iptables之centos6版本详解
    iptables之centos6版本常用设置
    iptables介绍iptables和netfilter
    git的使用学习(九)搭建git服务器
    js 图片预览
    ps -ef | grep java 查看所有关于java的进程
  • 原文地址:https://www.cnblogs.com/sweetlittlebaby/p/13460568.html
Copyright © 2020-2023  润新知