POJ3694-Network(Tarjan缩点+LCA)

题目链接


题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥。

思路:用Tarjan缩点后,形成一棵树,所以树边都是桥了。然后加入边以后,查询LCA,LCA上的桥都减掉。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <utility>
#include <algorithm>

using namespace std;

const int MAXN = 100005;

struct Edge{
    int to, next;
}edge[MAXN * 5];
int head[MAXN], tot;
int Low[MAXN], DFN[MAXN];
int Index, top;
int bridge;
int n, m;
int f[MAXN], ancestor[MAXN];

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

bool Union(int a, int b) {
    int pa = find(a);
    int pb = find(b);
    if (pa != pb) {
        f[pa] = pb;
        return true;
    }
    return false;
}

void addedge(int u, int v) {
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u, int pre) {
    int v;
    Low[u] = DFN[u] = ++Index;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        v = edge[i].to;
        if (v == pre) continue; 
        if (!DFN[v]) {
            Tarjan(v, u); 
            ancestor[v] = u;
            if (Low[u] > Low[v]) Low[u] = Low[v];
            if (Low[v] > DFN[u]) 
                bridge++;  
            else 
                Union(u, v);
        } 
        else if (Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
}

void init() {
    memset(head, -1, sizeof(head));
    memset(DFN, 0, sizeof(DFN)); 
    tot = 0;
    Index = top = 0;
    bridge = 0;
    memset(ancestor, 0, sizeof(ancestor));
    for (int i = 1; i <= n; i++)
        f[i] = i;
}

void solve() {
    for (int i = 1; i <= n; i++)
        if (!DFN[i])
            Tarjan(i, -1);
}

void lca(int u, int v) {
    while (u != v) {
        while (DFN[u] >= DFN[v] && u != v) {
            if (Union(u, ancestor[u]))  
                bridge--;
            u = ancestor[u];
        }
        while (DFN[v] >= DFN[u] && u != v) {
            if (Union(v, ancestor[v]))  
                bridge--;
            v = ancestor[v];
        }
    }
}

int main() {
    int t = 1;
    while (scanf("%d%d", &n, &m)) {
        if (n == 0 && m == 0) break;
        init(); 
        int u, v;  
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v); 
            addedge(u, v);
            addedge(v, u);
        }
        solve();

        printf("Case %d:\n", t++);
        int k;
        scanf("%d", &k);
        while (k--) {
            scanf("%d%d", &u, &v); 
            lca(u, v);
            printf("%d\n", bridge);
        }
        printf("\n");
    }
    return 0;
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。