zoukankan      html  css  js  c++  java
  • 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:
    ", t++);
            int k;
            scanf("%d", &k);
            while (k--) {
                scanf("%d%d", &u, &v); 
                lca(u, v);
                printf("%d
    ", bridge);
            }
            printf("
    ");
        }
        return 0;
    }
    


  • 相关阅读:
    2012的目标
    让顺丰快递给折腾了,昨晚发的快递,现在还没挪地方
    做的FM收音机终于交工,老婆验收完毕
    C语言宏定义使用技巧
    20棵树植树问题
    C简单实现动态2维数组
    运动量测试
    #pragma pack(n)的含义及其用法
    回调函数
    ubuntu 全局配置文件
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6836041.html
Copyright © 2011-2022 走看看