Network HDU - 2460 POJ - 3649

原题hdu链接 原题poj链接

  • 题解:做得比较通透的题,首先知道一条性质,边双连通分量缩点后会变成一棵树。要想知道加边后还有几个桥,那就相当于在一棵树上加边,找到这两个点的最近公共祖先,然后就可以找到经过了多少条边,这些全是桥,并且当经过后,这些桥都不再起作用了。
  • 代码:
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>

using namespace std;
const int N = 101000;
const int M = 401000;
int h[M], ne[M], to[M], idx;
int dfn[N], low[N], times;
int stk[N], top;
int id[N];
int ans, e_dcc;
int U[M], V[M];
void add(int u, int v) {ne[idx] = h[u], to[idx] = v, h[u] = idx++;}
void tarjan(int u, int from) {
    dfn[u] = low[u] = ++times;
    stk[++top] = u;
    bool flag = 1;
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int v = to[i];
        if ((i^1) == from && flag) {flag = 0;continue;}
        if (!dfn[v]) {
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) {
                ans++;
            }
        } else
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        e_dcc++;
        while (1) {
            id[stk[top]] = e_dcc;
            if (stk[top--] == u)break;
        }
    }
}
int dep[N];
int pre[N];
bool bridge[N];
void init() {
    memset(h, -1, sizeof h);
    memset(dfn, 0, sizeof dfn);
    memset(bridge, 0, sizeof bridge);
    memset(dep, 0, sizeof dep);
    idx = times = ans = e_dcc=top =0;
}

void dfs(int u, int fa) {
    if (fa == -1)dep[u] = 1;
    else dep[u] = dep[fa] + 1, pre[u] = fa;
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = to[i];
        if (dep[v] == 0)dfs(v, u);
    }
}
void lca(int x, int y) {
    if (dep[x] < dep[y])swap(x,y);
    while (dep[x] > dep[y]) {
        if (bridge[x])bridge[x] = 0,ans--;
        x = pre[x];
    }
    while (x != y) {
        if (bridge[x]) bridge[x] = 0, ans--;
        x = pre[x];
        if (bridge[y]) bridge[y] = 0, ans--;
        y = pre[y];
    }
}
void solve() {
    int n, m;
    int cas = 0;
while (~scanf("%d%d", &n, &m)) {
    if (n == 0 && m == 0)break;
    init();
    for (int i = 1; i <= m; i ++) {
        scanf("%d%d", &U[i], &V[i]);int u = U[i],v = V[i];
        add(u, v);
        add(v, u);
    }
    for (int i = 1; i <= n; i ++) {
        if (!dfn[i])tarjan(i, -1);
        bridge[i]=1;
        dep[i] = 0;
    }
    memset(h, -1, sizeof h);idx = 0;
    for (int i = 1; i <= m; i ++) {
        int u = U[i], v = V[i];
        if (id[u] == id[v])continue;
        add(id[u], id[v]);
        add(id[v], id[u]);
    }
    dfs(1, -1);
    int q;scanf("%d", &q);
    printf("Case %d:\n", ++cas);
    while (q--) {
        int u, v;scanf("%d%d", &u, &v);
        lca(id[u], id[v]);
        printf("%d\n", ans);
    }puts("");
}
}
int main() {
    int t = 1;//cin >> t;
    while (t--)solve();
    return 0;
}
posted @ 2021-04-08 16:01  u_yan  阅读(39)  评论(0编辑  收藏  举报