# BZOJ1123_BLO
解:
如书,去掉i相连的边之后:
1、若i不为割点,有ans[i]=2*(n-1)
2、若i为割点:
设搜索树上i的子节点中满足dfn[x]<=low[y]的所有子节点y有t个
去掉i后,会分成以下几个连通块:
1、i本身
2、以y1,y2,...yt为根的子树
3、剩下的部分
综上,当i是割点:
\[\large ans[i]=siz[s_{1}]*(n-siz[s_{1}])+siz[s_{2}]*(n-siz[s_{2}])+...+siz[s_{t}]*(n-siz[s_{t}]) \\
\large +1*(n-1)+\Bigg(n-1-\sum_{k=1}^{t}siz[s_{k}]\Bigg)*\Bigg(1+\sum_{k=1}^{t}siz[s_{k}]\Bigg)
\]
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
const int M = 500010;
int n, m;
int head[N], nxt[M << 1], ver[M << 1], tot;
ll siz[N]; int num;
int dfn[N], low[N];
ll ans[N];
void add(int u, int v) { ver[++tot] = v; nxt[tot] = head[u]; head[u] = tot; }
bool vis[N];
void dfs(int now) {
vis[now] = true;
siz[now] = 1;
for (int i = head[now]; i; i = nxt[i]) {
int y = ver[i];
if (vis[y]) continue;
dfs(y);
siz[now] += siz[y];
}
}
void tarjan(int now) {
dfn[now] = low[now] = ++num;
int cnt = 0;
ll sum = 0;
for (int i = head[now]; i; i = nxt[i]) {
int y = ver[i]; int x = now;
if (dfn[y] == 0) {
tarjan(y);
low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
cnt++;
// ans = ans + siz[y] * (n - siz[y]);
ans[now] = ans[now] + siz[y] * (n - siz[y]);
sum += siz[y];
}
}
else low[x] = min(low[x], dfn[y]);
}
if ((cnt != 0) && (now != 1 || cnt >= 2))
ans[now] = ans[now] + (n - 1) + (ll)(n - 1 - sum) * (1 + sum);
else ans[now] = 2 * (n - 1);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
if (u == v) continue;
add(u, v); add(v, u);
}
dfs(1);
tarjan(1);
for (int i = 1; i <= n; i++)
printf("%lld\n", ans[i]);
return 0;
}