Network POJ - 3694

题面

传送门

题解

缩点边双没跑了, 主要是算答案

采用靠并查集爬树的思想

int h[N], to[M << 2], ne[M << 2], tot;
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }

int dfn[N], df, st[N], low[N];
int c[N], ecnt, top;
void tarjan(int x, int bian) {
    dfn[st[++top] = x] = low[x] = ++df;
    for (int i = h[x]; i; i = ne[i]) {
        int y = to[i];
        if (!dfn[y]) tarjan(y, i), umin(low[x], low[y]);
        else if (i != (bian ^ 1)) umin(low[x], dfn[y]);
    }
    if (low[x] == dfn[x]) {
        ++ecnt; int y;
        do c[y = st[top--]] = ecnt; while (y != x);
    }
}

int f[N], dep[N], ans, pre[N];

int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }

void dfs(int x, int fa) {
    pre[x] = fa; dep[x] = dep[fa] + 1;
    for (int i = h[x]; i; i = ne[i]) {
        int y = to[i];
        if (y == fa) continue;
        dfs(y, x);
    }
}

void lca(int x, int y) {
    x = find(x), y = find(y);
    while (x != y) {
        if (dep[x] > dep[y]) { st[++top] = x; x = find(pre[x]); }
        else { st[++top] = y; y = find(pre[y]); }
        --ans;
    }
    while (top) f[st[top--]] = x;
}

int main() {
    IOS; int cas = 0;
    while (cin >> n >> m, n && m) {
        cout << "Case " << ++cas << ":\n";
        df = ecnt = ans = 0; tot = 1;
        rep(i, 1, n) h[i] = dfn[i] = 0;
        rep(i, 1, m) {
            int u, v; cin >> u >> v;
            add(u, v); add(v, u);
        }
        tarjan(1, -1);
        rep(i, 1, ecnt) h[i] = 0, f[i] = i;
        for (int i = tot; i >= 2; i -= 2) {
            int u = c[to[i ^ 1]], v = c[to[i]];
            if (u == v) continue;
            add(u, v); add(v, u); ++ans;
        }
        dfs(1, 0);
        for (cin >> _; _; --_) {
            int u, v; cin >> u >> v; lca(c[u], c[v]);
            cout << ans << '\n';
        } cout << '\n';
    }
    return 0;
}
posted @ 2020-12-09 21:40  洛绫璃  阅读(72)  评论(0编辑  收藏  举报