一开始没看懂样例,连去掉的点都算……
显然如果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 ",ans[i]); }