[bzoj1123] BLO

1123: [POI2008]BLO

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2222  Solved: 1090
[Submit][Status][Discuss]

Description

Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通。

Input

输入n<=100000 m<=500000及m条边

Output

输出n个数,代表如果把第i个点去掉,将有多少对点不能互通。

Sample Input

5 5
1 2
2 3
1 3
3 4
4 5

Sample Output

8
8
16
14
8

HINT

Source

题意:

极其简洁啊……

题解:

缩完点双后原图会变为一棵树。

每删掉一个割点,它的子树之间两两不能连接,子树与子树外的点两两不能连接。

然后惊奇的发现这题的点对要算上被删去的那个点。GG。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define MAXN 100005
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long

ll hd[MAXN],to[MAXM<<1];
ll nxt[MAXM<<1],siz[MAXN];
ll dfn[MAXN],low[MAXN];
ll N,M,ans[MAXN],cnt,num;

inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x*f;
}

inline void tarjan(ll u){
    dfn[u]=low[u]=++num;
    ll cutnum=0;siz[u]=1;
    for(ll i=hd[u];i;i=nxt[i]){
        ll v=to[i];
        if(dfn[v]) low[u]=min(low[u],dfn[v]);
        else{
            tarjan(v);siz[u]+=siz[v];
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v]){
                ans[u]+=(cutnum*siz[v]);
                cutnum+=siz[v];
            }
        }
    }
    ans[u]+=(cutnum*(N-cutnum-1));
    return;    
}

inline void addedge(ll u,ll v){
    to[++cnt]=v,nxt[cnt]=hd[u];
    hd[u]=cnt;return;    
}

int main(){
    N=read(),M=read();
    for(ll i=1;i<=M;i++){
        ll u=read(),v=read();
        addedge(u,v),addedge(v,u);
    }
    for(ll i=1;i<=N;i++)
        if(!dfn[i])
            tarjan(i);
    for(ll i=1;i<=N;i++)
        printf("%lld
",ans[i]*2+(N-1)*2);
    return 0;
}
原文地址:https://www.cnblogs.com/YSFAC/p/9914640.html