一开始没看懂样例,连去掉的点都算……
显然如果i不是割点,那么ans[i]=(n-1)*2,
如果i是割点,ans[i]=将i去掉后生成的联通块大小两两相乘的和加上i本身,但这样并不好算,换一种思路,在求割点时记录搜索树中以x为根的子树大小,
(式子太长不想打了……)
#include<iostream>
#include<cstdio>
#define int long long
#define MAXN 100010
using namespace std;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[MAXN*10];
int first[MAXN],num_e;
#define f(x) first[x]
int n,m;
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
int dfn[MAXN],low[MAXN],size[MAXN],cnt,root;
bool iscut[MAXN];
int ans[MAXN];
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
int flag=0,sum=0;size[x]=1;
for(int i=f(x);i;i=n(i))
if(!dfn[v(i)])
{
tarjan(v(i)),low[x]=min(low[x],low[v(i)]);
size[x]+=size[v(i)];
if(low[v(i)]>=dfn[x])
{
flag++;
ans[x]+=size[v(i)]*(n-size[v(i)]);sum+=size[v(i)];
if(x!=root || flag>1)iscut[x]=1;
}
}
else low[x]=min(low[x],dfn[v(i)]);
if(iscut[x])ans[x]+=(n-sum-1)*(sum+1)+n-1;
else ans[x] =(n-1)*2;
}
signed main()
{
scanf("%lld%lld",&n,&m);
int a,b;
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&a,&b);
if(a!=b)add(a,b);add(b,a);
}
for(int i=1;i<=n;i++)
if(!dfn[i]){root=i;tarjan(i);}
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]);
}