POJ 3694 Network (tarjan + LCA)

题目链接:http://poj.org/problem?id=3694

题意是给你一个无向图n个点,m条边,将m条边连接起来之后形成一个图,有Q个询问,问将u和v连接起来后图中还有多少个桥。

首先用tarjan标记点的low和dfn值,那么u和v相连的边是桥的条件是dfn[u] < low[v](说明v与u不在一个连通分量里面,v无法通过回溯到达u点,画个图模拟会清楚)。那么bridge[v]++表示u与v相连的边是桥(若是标记bridge[u]++,则最后的答案可能会出错,亲测)。要是u和v相连,不属于同一个连通分量的话会形成一个环路,那么环路里所有的桥都没有了,所以用LCA将u和v一边找公共祖节点,一边消除桥。

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 const int MAXN = 2e5 + 5;
  7 struct data {
  8     int next , to;
  9 }edge[MAXN * 4];
 10 int head[MAXN] , block[MAXN] , low[MAXN] , dfn[MAXN] , st[MAXN] , dep[MAXN] , par[MAXN] , bridge[MAXN];
 11 int top , ord , sccnum , cont , ans;
 12 bool instack[MAXN];
 13 
 14 void init() {
 15     memset(head , -1 , sizeof(head));
 16     memset(low , 0 , sizeof(low));
 17     memset(dfn , 0 , sizeof(dfn));
 18     memset(instack , false , sizeof(instack));
 19     memset(bridge , 0 , sizeof(bridge));
 20     top = ord = sccnum = cont = ans = 0;
 21 }
 22 
 23 inline void add(int u , int v) {
 24     edge[cont].next = head[u];
 25     edge[cont].to = v;
 26     head[u] = cont++;
 27 }
 28 
 29 void tarjan(int u , int p , int d) {
 30     low[u] = dfn[u] = ++ord;
 31     st[++top] = u;
 32     instack[u] = true;
 33     par[u] = p;
 34     dep[u] = d;
 35     for(int i = head[u] ; ~i ; i = edge[i].next) {
 36         int v = edge[i].to;
 37         if(v == p)
 38             continue;
 39         if(!dfn[v]) {
 40             tarjan(v , u , d + 1);
 41             low[u] = min(low[v] , low[u]);
 42             if(dfn[u] < low[v]) {
 43                 bridge[v]++;
 44                 ans++;
 45             }
 46         }
 47         else if(instack[v]) {
 48             low[u] = min(low[u] , dfn[v]);
 49         }
 50     }
 51     if(low[u] == dfn[u]) {
 52         int v;
 53         sccnum++;
 54         do {
 55             v = st[top--];
 56             instack[v] = false;
 57             block[v] = sccnum;
 58         }while(u != v);
 59     }
 60 }
 61 
 62 void lca(int u , int v) {
 63     while(dep[u] < dep[v]) {
 64         if(bridge[v]) {
 65             ans--;
 66             bridge[v]--;
 67         }
 68         v = par[v];
 69     }
 70     while(dep[u] > dep[v]) {
 71         if(bridge[u]) {
 72             ans--;
 73             bridge[u]--;
 74         }
 75         u = par[u];
 76     }
 77     while(v != u) {
 78         if(bridge[u]) {
 79             bridge[u]--;
 80             ans--;
 81         }
 82         if(bridge[v]) {
 83             bridge[v]--;
 84             ans--;
 85         }
 86         u = par[u];
 87         v = par[v];
 88     }
 89 }
 90 
 91 int main()
 92 {
 93     int n , m , u , v , q , Case = 1;
 94     while(~scanf("%d %d" , &n , &m) && (n || m)) {
 95         init();
 96         while(m--) {
 97             scanf("%d %d" , &u , &v);
 98             add(u , v);
 99             add(v , u);
100         }
101         tarjan(1 , -1 , 0);
102         scanf("%d" , &q);
103         printf("Case %d:
" , Case++);
104         while(q--) {
105             scanf("%d %d" , &u , &v);
106             if(block[u] == block[v]) {
107                 printf("%d
" , ans);
108                 continue;
109             }
110             lca(u , v);
111             printf("%d
" , ans);
112         }
113         putchar('
');
114     }
115 }
原文地址:https://www.cnblogs.com/Recoder/p/5267176.html