题面
题解
深度优先遍历这幅图。
设
s
i
z
[
x
]
siz[x]
siz[x] 表示在搜索树中,以
x
x
x 为根的子树的大小。
注意不连通的关系是双向的,所以
(
x
,
y
)
,
(
y
,
x
)
(x,y),(y,x)
(x,y),(y,x)算两次。
对于当前点
x
x
x,有两种情况:
-
x
x
x 是割点
那么删去 x x x 之后会有如下的点不连通:-
x
x
x 在搜索树上的子树中所有的节点与其它的点:
∑ k = 1 t s i z [ k ] ∗ ( n − s i z [ k ] ) ( t 为 子 节 点 总 数 ) \sum_{k = 1}^{t}siz[k] * (n - siz[k])(t为子节点总数) k=1∑tsiz[k]∗(n−siz[k])(t为子节点总数) - x x x 与其余的 n − 1 n - 1 n−1 个节点。
-
x
x
x 的祖先节点和
x
x
x 的祖先节点的兄弟姐妹节点,与
x
x
x以及它的子树:
( n − 1 − ∑ k = 1 t s i z [ k ] ) × ( 1 + ∑ k = 1 t s i z [ k ] ) (n - 1 -\sum_{k = 1}^{t}siz[k]) \times(1 + \sum_{k = 1}^{t}siz[k] ) (n−1−k=1∑tsiz[k])×(1+k=1∑tsiz[k])
-
x
x
x 在搜索树上的子树中所有的节点与其它的点:
-
x
x
x 不是割点
那么删去与 x x x 相连的边之后不会影响除 x x x 以外的节点的连通性。所以只有 x x x 与其它节点不连通。
a n s = 2 × ( n − 1 ) ans = 2 \times (n - 1) ans=2×(n−1)
于是我们在 t a r j a n tarjan tarjan 求割点的同时求出以上的值,就能得到答案了。
代码如下
#include<cstdio>
#include<iostream>
using std::min;
const int N = 1e5 + 5,M = 5e5 + 5;
struct edge {
int next,to;
}a[M << 1];
int head[N],n,m,a_size = 1,root;
inline void add(int u,int v) {
a[++a_size] = (edge){head[u],v};
head[u] = a_size;
a[++a_size] = (edge){head[v],u};
head[v] = a_size;
}
int dfn[N],low[N],siz[N],num = 0;
long long ans[N]; bool cut[N];
void tarjan(int x) {
dfn[x] = low[x] = ++num;
int flag = 0,sum = 0; siz[x] = 1;
for(int i = head[x]; i; i = a[i].next) {
int y = a[i].to;
if(!dfn[y]) {
tarjan(y); siz[x] += siz[y];
low[x] = min(low[x],low[y]);
if(low[y] >= dfn[x]) {
flag++; sum += siz[y];
ans[x] += 1ll * siz[y] * (n - siz[y]);
if(x != root || flag > 1) cut[x] = true;
}
}
else low[x] = min(low[x],dfn[y]);
}
if(cut[x]) ans[x] += 1ll * (n - 1 - sum) * (1 + sum) + n - 1;
else ans[x] = (n - 1) << 1;
}
inline int read() {
int x = 0,flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')flag = -1;ch = getchar();}
while(ch >='0' && ch <='9'){x = (x << 3) + (x << 1) + ch - 48;ch = getchar();}
return x * flag;
}
int main() {
n = read(),m = read();
for(int i = 1; i <= m; i++) {
int u = read(),v = read();
add(u,v);
}
for(int i = 1; i <= n; i++) {
if(dfn[i]) continue;
root = i; tarjan(root);
}
for(int i = 1; i <= n; i++) printf("%lld\n",ans[i]);
return 0;
}