求割点,然后所有连通块大小互乘
我一开始只想到n^2扫一遍求和…
但是大家貌似都是在dfs的时候就已经在算ans了:对于每一个割点,dfs树中它以上的部分和它的每个子树就是不同的连通块
详见代码注释
#include<cstdio>
#include<vector>
#define N 100000
#define LL long long
using namespace std;
inline int read()
{
int a=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){a=a*10+c-'0';c=getchar();}
return a*f;
}
vector<int>e[N+5];
int n,m,clo;
int low[N+5],dfn[N+5],sz[N+5];
LL ans[N+5];
void tarjan(int x)
{
int t=0;sz[x]=1; //t=已经搜过的子树大小和
dfn[x]=low[x]=++clo;
for(int i=0;i<e[x].size();++i)
if(dfn[e[x][i]]) low[x]=min(low[x],dfn[e[x][i]]);
else
{
tarjan(e[x][i]);
sz[x]+=sz[e[x][i]];
low[x]=min(low[x],low[e[x][i]]);
if(dfn[x]<=low[e[x][i]])
{
ans[x]+=1ll*t*sz[e[x][i]];
t+=sz[e[x][i]];
}
}
ans[x]+=1ll*t*(n-t-1); //和它之上的乘一乘
}
int main()
{
n=read(),m=read();
int i,x,y;
for(i=1;i<=m;++i)
{
x=read(),y=read();
e[x].push_back(y),e[y].push_back(x);
}
tarjan(1);
for(i=1;i<=n;++i)
printf("%lld\n",(ans[i]+n-1)*2ll); //包括这个点能到达的(+n-1),有序数对(*2)
return 0;
}