B 城有 n 个城镇,m 条双向道路。
每条道路连结两个不同的城镇,没有重复的道路,所有城镇连通。
把城镇看作节点,把道路看作边,容易发现,整个城市构成了一个无向图。
输入格式
第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 a 和 b,表示城镇 a 和 b 之间存在一条道路。
输出格式输出共 nn 行,每行输出一个整数。
第 i 行输出的整数表示把与节点 ii 关联的所有边去掉以后(不去掉节点 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
分析:这是一个求割点的题 ,以此来判断点u去掉后其子节点是不是被断开,是的话就ans[u]+=(long long)(n-num[v])*num[v];,最后再加一下没有被断开的节点开头的有序数对,以及以u开头的有序数对。
代码如下:
#include <iostream>
#include <vector>
using namespace std;
const int N=1e5+10;
vector<int>adj[N];
int low[N],dfn[N],num[N];
long long ans[N];
int n,m,cnt;
void tarjan(int fa,int u)
{
int res=0;
low[u]=dfn[u]=++cnt;
num[u]=1;
for(auto v:adj[u])
{
if(fa==v)continue;
if(dfn[v]) low[u]=min(dfn[v],low[u]);
else
{
tarjan(u,v);
low[u]=min(low[v],low[u]);
num[u]+=num[v];
if(dfn[u]<=low[v])
{
res+=num[v];
ans[u]+=(long long)(n-num[v])*num[v];
}
}
}
ans[u]+=(long long)(n-res-1)*(res+1)+(n-1);
}
int main()
{
cin>>n>>m;
while(m--)
{
int x,y;
cin>>x>>y;
adj[x].push_back(y);
adj[y].push_back(x);
}
tarjan(0,1);
for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
return 0;
}