1123: [POI2008]BLO

1123: [POI2008]BLO

Time Limit: 10 Sec  Memory Limit: 162 MB
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1123

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

题意叙述不清。

题目大意:给定N个点M条边的无向图,问删除每个点后,对于有序数对(x,y)满足x,y互不连通的数对数。其中,被删掉的点也应被统计。

这种和删点,联通有关的,可以考虑割点/点双联通分量。

题解:这一题中蕴含的技巧就是求割点时计算其将图分成了多少个大小为多少的连通块。 
因为答案就是这些连通块大小互相乘的和。 
关键在于,再求割点时维护一个vis[i]代表搜索树中这个子树的大小。 
因为一个割点将图分成的连通块是其下面的所有子树(互不相连)与这个点上面的所有点。tmp表示这个点的子树之前的同父亲子树的和。为什么这么算可以得到答案,可以自己推一推。 
不要忘记最后答案要乘2。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100005, maxm = 1000005;
int n,m,dfn[maxn],tot,low[maxn],idx,h[maxn];
ll siz[maxn], ans[maxn];
struct edge{
    int v,nxt;
}G[maxm];
void add(int u, int v){
    G[++tot].v = v;G[tot].nxt = h[u]; h[u] = tot;
}
 
void tarjan(int u, int f){
    dfn[u] = low[u] = ++idx;
    siz[u] = 1;
    ll t = 0;
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        if(dfn[v])low[u] = min(low[u], dfn[v]);
        else {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            siz[u] += siz[v];
            if(dfn[u] <= low[v]){//
                 
                ans[u] += siz[v] * t;
                t += siz[v];            
            }
        }
    }
    ans[u] += (n - t - 1) * t;
}
 
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= m; i++){
        int u, v;
        scanf("%d%d",&u,&v);
        add(u, v); add(v, u);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i])tarjan(i, -1);
    for(int i = 1; i <= n; i++)
        printf("%lld\n",(ans[i]+n-1)*2);
}
View Code

猜你喜欢

转载自www.cnblogs.com/EdSheeran/p/9029346.html