题意:
由题知,应该对点的类型分类处理。
如果点
单独为一个连通块; - 每个子节点及其子树各自构成一个连通块;
- 除以上所有点之外的点构成一个连通块。
我们设一个数组
如果点
所以只用把割点求出来,一次求每个点的值即可。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
int head[501010],cnt;
int Index,cut[101010];
int dfn[101010],low[101010];
long long size[101010],ans[101010];
struct node
{
int next;
int to;
}e[2010100];
void add(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++Index;
size[u]=1;
int sum=0,flag=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
size[u]+=size[v];
if(low[v]>=dfn[u])
{
flag++;
ans[u]+=(long long)size[v]*(n-size[v]);
sum+=size[v];
if(u!=1||flag>1)
cut[u]=1;
}
}
else
low[u]=min(low[u],dfn[v]);
}
if(cut[u])
ans[u]+=(long long)(n-sum-1)*(sum+1)+(n-1);
else
ans[u]=2*(n-1);
}
int main()
{
scanf("%d%d",&n,&m);
cnt=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;
}