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:\n" , Case++);
104         while(q--) {
105             scanf("%d %d" , &u , &v);
106             if(block[u] == block[v]) {
107                 printf("%d\n" , ans);
108                 continue;
109             }
110             lca(u , v);
111             printf("%d\n" , ans);
112         }
113         putchar(‘\n‘);
114     }
115 }
时间: 2024-10-13 08:24:30

POJ 3694 Network (tarjan + LCA)的相关文章

Poj 3694 Network (连通图缩点+LCA+并查集)

题目链接: Poj 3694 Network 题目描述: 给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥? 解题思路: 先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条边两个端点根节点的LCA,统计其中的桥,然后把这个环中的节点加到一个集合中,根节点标记为LCA. 题目不难,坑在了数组初始化和大小 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #inclu

POJ 3694——Network——————【连通图,LCA求桥】

Network Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3694 Description A network administrator manages a large network. The network consists of N computers and M links between pairs of compute

poj 3694 Network (桥入门)

1 /******************************************** 2 Network(POJ 3694) 3 http://poj.org/problem?id=3694 4 桥入门题 + LCA(树中最小公共祖先) 5 做这题必须要会用邻接表(做这题才学会),因为 6 给的边有重边,用vector不好记录重边. 7 8 ********************************************/ 9 10 #include<iostream> 11

POJ - 3694 Network(tarjan+lca)

题意:给出一个无相图,然后q次新增加边,问在添加边的过程中桥的数目当且仅当无向边(u,v)为树枝的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u-v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥思路:首先我们知道在给定一张图之后,不断添加边,桥的数目只会减少而不是增加tarjan的使用就是缩点,将一个连通分量缩成一个点,那么那个连通分量中的边都不会是桥同时缩完点之后我们就会发现,桥其实就是新形成的树的边在添加的过程中,如果是在连通分量内就

POJ 3694 Network ——(桥 + LCA)

题意:给n个点和m条边,再给出q条边,问每次加一条边以后剩下多少桥. 分析:这题是结合了LCA和dfn的妙用._dfn数组和dfn的意义不一样,并非访问的时间戳,_dfn表示的是被访问的顺序,而且是多线程访问下的顺序,举个例子,同一个点分岔开来的点,距离这个点相同距离的点,他们的_dfn的值是相同的,而dfn不是,类似于单线程dfs访问的各点的dfn值是不同的. 具体见代码: 1 #include <stdio.h> 2 #include <algorithm> 3 #includ

poj 3694 Network(桥+lca)

给定一个无向无环图,保证连通,求每加入一条给定的边图中还剩下多少桥. 双联通缩点重新建图后,再用lca在线算法解. lca算法参考斌神http://www.cnblogs.com/kuangbin/p/3184884.html 这个版本的lca思路大致是先topsort,再用并查集分别从查询的两点向根节点回溯,直到两个点碰撞.效率我分析不出来,但看得出效率很高,每次查询都对后面查询做了工作. 代码: #include<iostream> #include<cstdio> #incl

POJ 3694 Network(无向图求桥+重边处理+LCA)

题目大意: 给你一个无向图,然后再给你一个Q代表有Q次询问,每一次加一条边之后还有几座桥.在这里要对重边进行处理. 每次加入一条边之后,在这条搜索树上两个点的公共祖先都上所有点的桥都没了. 这里重边的处理上要说一下, 我以前第一写的时候根本没考虑这个问题,但是居然过了...过了...  很扯淡,但是重边的问题确实是存在. 这里我们 使用一个 bridge 数组来保存桥, 因为有重边的存在  只有 bridge 数量为 1 的时候这个路径才算是桥,否则则不是桥 bridge[i] 是指  i 和

POJ 3694 Network

Network Time Limit: 5000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 369464-bit integer IO format: %lld      Java class name: Main A network administrator manages a large network. The network consists of N computers and M

[双连通分量] POJ 3694 Network

Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9434   Accepted: 3511 Description A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers