分析
对每个点的贡献进行分析:如果这个点不是割点,那么去掉这个点图仍然联通,减少的访问仅为这个点和其他点之间的联系,也就是(2*(n-1))。如果这个点是割点,那么去除之后图会变成多个联通块。设第(i)个联通块的大小为(size_i),易知联通块之间减少的联系是(Sigma_iSigma_j size_isize_j)。对这个式子做变形,得到(Sigma_i size_i(n-size_i-1))。于是可以在tarjan的同时求出这个值。把所有贡献加一起就好了。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T>inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write (T x) {
if (x<0) putchar('-'),x=-x;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Fate {
#define int long long
const int N=500500;
int n,m;
int cnt;
int head[N];
struct node {
int to,next;
} edge[N<<1];
int index;
int dfn[N],low[N],size[N],cut[N];
int ans[N];
inline void add (int a,int b) {
edge[++cnt].to=b,edge[cnt].next=head[a],head[a]=cnt;
}
void tarjan (int now) {
int tmp=0;size[now]=1,dfn[now]=low[now]=++index;
for (register int i=head[now]; i; i=edge[i].next) {
int to=edge[i].to;
if (!dfn[to]) {
tarjan(to);
size[now]+=size[to];
low[now]=min(low[now],low[to]);
if (dfn[now]<=low[to]) {
ans[now]+=tmp*size[to];
tmp+=size[to];
}
} else {
low[now]=min(low[now],dfn[to]);
}
}
ans[now]+=tmp*(n-tmp-1);
}
inline void Stay_Night () {
read(n),read(m);
for (register int i=1; i<=m; ++i) {
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
tarjan(1);
for (register int i=1; i<=n; ++i) {
write((ans[i]+n-1)*2),putchar('
');
}
}
#undef int
}
int main () {
Fate::Stay_Night();
}