# 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;
}
posted @ 2020-08-04 10:15  熹圜  阅读(111)  评论(0编辑  收藏  举报