B城有 n 个城镇,m 条双向道路。
每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。
输入格式
第一行包含两个整数 n 和 m。
接下来m行,每行包含两个整数 a 和 b,表示城镇 a 和 b 之间存在一条道路。
输出格式
输出共n行,每行输出一个整数。
第 i 行输出的整数表示把与节点 i 关联的所有边去掉以后(不去掉节点 i 本身),无向图有多少个有序点(x,y),满足 x 和 y 不连通。
数据范围
n≤100000,m≤500000
输入样例:
5 5
1 2
2 3
1 3
3 4
4 5
输出样例:
8
8
16
14
8
思路: 每个点删掉,会剩下3种东西:
(1)他自己(2)删掉某边剩下的连通分量(3)剩下的连通分量
那么就是这几部分组合起来的答案。大小分别是1,size1,size2,size3…sizek,(n - 1 - ∑size)。答案就是这一块的答案乘以其与n的差。这可以在tarjan的过程求出来。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000000 + 7;
int head[maxn],to[maxn],nex[maxn],tot;
int dfn[maxn],low[maxn],dfs_clock;
int size[maxn],cut[maxn];
ll ans[maxn];
int n,m;
void add(int x,int y)
{
to[++tot] = y;
nex[tot] = head[x];
head[x] = tot;
}
void tarjan(int x)
{
low[x] = dfn[x] = ++dfs_clock;
int flag = 0,sum = 0;
size[x] = 1;
for(int i = head[x];i;i = nex[i])
{
int y = to[i];
if(!dfn[y])
{
tarjan(y);
size[x] += size[y];
low[x] = min(low[x],low[y]);
if(dfn[x] <= low[y])
{
flag++;
sum += size[y];
ans[x] += (ll)size[y] * (n - size[y]);
if(x != 1 || flag >= 2)
cut[x] = 1;
}
}
else
low[x] = min(low[x],dfn[y]);
}
if(cut[x])
ans[x] += (ll)(n - sum - 1) * (sum + 1) + (n - 1);
else
ans[x] = 2 * (n - 1);
}
int main()
{
scanf("%d%d",&n,&m);
tot = 1;
for(int i = 1;i <= m;i++)
{
int x,y;scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
tarjan(1);
for(int i = 1;i <= n;i++)
printf("%lld\n",ans[i]);
return 0;
}