(x,y)(y,x)都要计算。
去掉某个点后:
如果y不是割点:、
则ans[y]+=2*(n-1)//此时只有2个联通块
如果y是割点:
则假设有t个儿子会被分离(即low[x]>=dfn[y]),会形成t+2个联通块。
因为还会有y的儿子xx low[xx]<dfn[y],即删去y,不会使得xx的子树分离。
所以对y来说结果是:
再tarjan的过程中求即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 5e5+7;
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
int n,m,root;
int dfn[M],low[M],num;
bool cut[M];//双向边
ll ans[M],siz[M];
void tarjan(int x)
{
// cout<<x<<"-- "<<endl;
siz[x]=1;
dfn[x]=low[x]=++num;
int flag=0;
ll sm=0;
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to;
if(!dfn[y])
{
// cout<<x<<" = "<<y<<endl;;
tarjan(y);
siz[x]+=siz[y];
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
{
flag++;
if(flag>=2||x!=root)
{
cut[x]=true;
ans[x]+=siz[y]*(n-siz[y]);
sm+=siz[y];
}
}
}
else low[x]=min(low[x],dfn[y]);
}
if(cut[x]) ans[x]+=(ll)(n-1)+(ll)(n-sm-1)*(sm+1);//(x,y) (y,x)都要计算
else ans[x]+=(n-1)*2;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
root=1,tarjan(1);
for(int i=1;i<=n;i++)
cout<<ans[i]<<endl;
return 0;
}