BZOJ 1123 [POI2008]BLO(Tarjan算法)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1123

 

【题目大意】

  Byteotia城市有n个towns,m条双向roads. 每条road连接两个不同的towns,
  没有重复的road. 所有towns连通。输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

 

【题解】

  Tarjan算法的基础应用,如果x是y分支的割点,那么y就参与x点的答案贡献计数,
  将割点为x的不同分支的size进行动态乘即可。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N=100010,M=500010;
int n,m,g[N],v[M<<1],nxt[M<<1],ed;
int dfn[N],low[N],num;
LL ans[N],size[N];
void add_edge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void tarjan(int x){
    dfn[x]=low[x]=++num;
    size[x]=1; LL tmp=0;
    for(int i=g[x];i;i=nxt[i])if(!dfn[v[i]]){
        int y=v[i];
        tarjan(y);
        size[x]+=size[y]; 
        if(low[x]>low[y])low[x]=low[y];
        if(dfn[x]<=low[y]){//x是割点
            ans[x]+=tmp*size[y];
            tmp+=size[y];
        }
    }else if(low[x]>dfn[v[i]])low[x]=dfn[v[i]];
    ans[x]+=tmp*(n-tmp-1);
}
void init(){ed=0;memset(g,0,sizeof(g));}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        memset(ans,0,sizeof(ans));
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            add_edge(x,y);
            add_edge(y,x);
        }tarjan(1);
        for(int i=1;i<=n;i++)printf("%lld\n",(ans[i]+n-1)<<1);
    }return 0;
}
posted @ 2017-04-17 12:37  forever97  阅读(314)  评论(0编辑  收藏  举报