bzoj1123 [POI2008]BLO

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1123

【题解】

tarjan算割点的时候顺便统计即可。

割点的条件是

low[to[i]]>=dfn[x],说明删掉点x这一段就不和其他联通了。

先算不包含祖先的其他连通块的贡献,最后加包含祖先的贡献即可。

这题输出方式奇怪啊。。具体见本题discuss

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e6 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m;
int head[M], nxt[M], to[M], tot=0;
inline void add(int u, int v) {
    ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
    add(u, v), add(v, u);
}

int dfn[M], low[M], sz[M], DFN=0;
ll ans[M];

inline void tarjan(int x, int fa=0) {
    ll t=0;
    dfn[x] = low[x] = ++DFN;
    sz[x] = 1;
    for (int i=head[x]; i; i=nxt[i]) {
        if(to[i] == fa) continue;
        if(!dfn[to[i]]) {
            tarjan(to[i], x);
            sz[x] += sz[to[i]];
            low[x] = min(low[x], low[to[i]]);
            if(low[to[i]] >= dfn[x]) {
                ans[x] += t*sz[to[i]];    
                t += sz[to[i]]; 
            }
        } else low[x] = min(low[x], dfn[to[i]]);
    }    
    ans[x] += t*(n-t-1);
}

int main() {
    cin >> n >> m;
    for (int i=1, u, v; i<=m; ++i) {
        scanf("%d%d", &u, &v);
        adde(u, v);
    }
    tarjan(1);
//    for (int i=1; i<=n; ++i) printf("%d %d
", dfn[i], low[i]);
    for (int i=1; i<=n; ++i) ans[i] = (ans[i] + n-1)*2;
    for (int i=1; i<=n; ++i) printf("%lld
", ans[i]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/galaxies/p/bzoj1123.html