试题分析
分两种情况考虑。
当此点不是割点是,答案是$2 imes (n-1)$。
当是割点时,我们发现这个点把树分成了若干个联通块,只要两两相乘即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int N=100001; const int M=500001; struct node{ int u,v,nex; }x[M<<1]; int head[N],cnt,n,m,dfn[N],low[N],num; void add(int u,int v){ x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; } int size[N],rt,ans[N]; void tarjan(int f,int fath){ dfn[f]=low[f]=++num;size[f]=1; int flag=0,st=0,sum=0; for(int i=head[f];i!=-1;i=x[i].nex){ if(x[i].v==fath) continue; if(!dfn[x[i].v]){ flag++; tarjan(x[i].v,f); size[f]+=size[x[i].v]; low[f]=min(low[f],low[x[i].v]); if((flag>1&&f==rt)||(dfn[f]<=low[x[i].v]&&f!=rt)){ ans[f]+=(size[x[i].v])*(n-size[x[i].v]); sum+=size[x[i].v]; st=1; } }else low[f]=min(low[f],dfn[x[i].v]); } if(!st) ans[f]=(n-1)*2; if(st) ans[f]+=(n-1+(n-sum-1)*(sum+1)); return; } signed main(){ memset(head,-1,sizeof(head)); n=read(),m=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(); add(u,v),add(v,u); } for(int i=1;i<=n;i++) if(!dfn[i]) rt=i,tarjan(i,0); for(int i=1;i<=n;i++) printf("%lld ",ans[i]); }