bzoj1123(割点)

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


只有割点会对答案有影响
通过乘法原理统计答案即可

#include<bits/stdc++.h>
using namespace std;
int n , m , linkk[101000] ,t;
int dfn[101000] , low[101000] , tot ;
long long son[101000];
bool check[101000];
int fa[101000];
struct node{
    int n , y;
}e[1010000]; 
int read() {
    bool flag=true;int num=0;char c=getchar(); 
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false; 
    for(;c>='0'&&c<='9';c=getchar()) num=(num<<3)+(num<<1)+c-48; 
    if(flag) return num;    else return -num; 
} 
void insert(int x,int y){
    e[++t].y = y;e[t].n = linkk[x];linkk[x] = t;
    e[++t].y = x;e[t].n = linkk[y];linkk[y] = t;
    return; 
}
void trajan(int x,int father){
    fa[x] = father;
    dfn[x] = low[x] = ++tot;
    int flag = 0;
    for(int i = linkk[x];i;i = e[i].n)
       if(!dfn[e[i].y]){
           int y = e[i].y;
           trajan(y,x);
           son[x] += son[y]; 
           low[x] = min(low[x] , low[y]);
           if(low[y] >= dfn[x]){
               flag++;
               if(x != 1 || flag > 1) check[x] = true;
           }
       }
       else low[x] = min(low[x],dfn[e[i].y]);
    son[x]++;
    return;
}
void init(){
    n = read();m = read();
    for(int i = 1;i <= m;++i){
        int x = read() , y = read();
        insert( x , y );
    }
    trajan(1 , 0);
    return;
}
void print(){
    long long ans;
    long long now;
    for(int i = 1;i <= n;++i)
     if(!check[i]) printf("%d\n",(n - 1) * 2); 
        else{
            ans = 0;
            now = 0;
            for(int j = linkk[i];j;j = e[j].n){
                int y = e[j].y;
                if(fa[y] != i) continue;
                if(low[y] >= dfn[i]) {
                   ans += 1ll * son[y] * ( n - son[y] - 1 );
                   now += son[y];  
                }
            }
            now = n - now - 1;
            if(now != 0)
                ans += now * ( n - now - 1 );
            ans = ans + (n - 1) * 2; 
            printf("%lld\n",ans);
        }
    return;
}
void work(){
    print();
    return;
}
int main(){
    init();
    work();
//  for(int i = 1;i <= n;++i)
//   printf("%d ",dfn[i]);printf("\n");
//  for(int i = 1;i <= n;++i)
//   printf("%d ",low[i]);printf("\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值