POJ3694(KB9-D 割边+LCA)

Network

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 10371   Accepted: 3853

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 are connected directly or indirectly by successive links, so data can be transformed between any two computers. The administrator finds that some links are vital to the network, because failure of any one of them can cause that data can‘t be transformed between some computers. He call such a link a bridge. He is planning to add some new links one by one to eliminate all bridges.

You are to help the administrator by reporting the number of bridges in the network after each new link is added.

Input

The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).
Each of the following M lines contains two integers A and B ( 1≤ A ≠ B ≤ N), which indicates a link between computer A and B. Computers are numbered from 1 to N. It is guaranteed that any two computers are connected in the initial network.
The next line contains a single integer Q ( 1 ≤ Q ≤ 1,000), which is the number of new links the administrator plans to add to the network one by one.
The i-th line of the following Q lines contains two integer A and B (1 ≤ A ≠ B ≤ N), which is the i-th added new link connecting computer A and B.

The last test case is followed by a line containing two zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) and Q lines, the i-th of which contains a integer indicating the number of bridges in the network after the first i new links are added. Print a blank line after the output for each test case.

Sample Input

3 2
1 2
2 3
2
1 2
1 3
4 4
1 2
2 1
2 3
1 4
2
1 2
3 4
0 0

Sample Output

Case 1:
1
0

Case 2:
2
0

Source

2008 Asia Hefei Regional Contest Online by USTC

割边:在连通图中,删除了连通图的某条边后,图不再连通。这样的边被称为割边,也叫做桥。
割点:在连通图中,删除了连通图的某个点以及与这个点相连的边后,图不再连通。这样的点被称为割点。
DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树。

树边:在搜索树中的蓝色线所示,可理解为在DFS过程中访问未访问节点时所经过的边,也称为父子边
回边:在搜索树中的橙色线所示,可理解为在DFS过程中遇到已访问节点时所经过的边,也称为返祖边、后向边
观察DFS搜索树,我们可以发现有两类节点可以成为割点。对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;对非叶子节点u(非根节点),若其中的某棵子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与该棵子树的节点不再连通;则节点u为割点。对于根结点,显然很好处理;但是对于非叶子节点,怎么去判断有没有回边是一个值得深思的问题。我们用dfn[u]记录节点u在DFS过程中被遍历到的次序号,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小),那么low[u]的计算过程如下。

对于给的例子,其求出的dfn和low数组如下。
id     123456
dfn   123456
low   111444
可以发现,对于情况2,当(u,v)为树边且low[v]≥dfn[u]时,节点u才为割点。而当(u,v)为树边且low[v]>dfn[u]时,表示v节点只能通过该边(u,v)与u连通,那么(u,v)即为割边。tarjan算法的时间复杂度是O(n+m)的,非常快。

题意:给出一幅无向图,然后进行加边,每加一条边,询问图中割边的数量

思路:每次加边,把u-v-lca(u,v)-u这个环上的割边减掉。

  1 //2017-08-20
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6
  7 using namespace std;
  8
  9 const int N = 100010;
 10 const int M = 200010;
 11 int head[N], tot;
 12 struct Edge{
 13     int to, next;
 14 }edge[M<<1];
 15
 16 void init(){
 17     tot = 0;
 18     memset(head, -1, sizeof(head));
 19 }
 20
 21 void add_edge(int u, int v){
 22     edge[tot].to = v;
 23     edge[tot].next = head[u];
 24     head[u] = tot++;
 25
 26     edge[tot].to = u;
 27     edge[tot].next = head[v];
 28     head[v] = tot++;
 29 }
 30
 31 int n, m, deep, ans;
 32 int dfn[N];//dfn[u]记录节点u在DFS过程中被遍历到的次序号
 33 int low[N]; //low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)
 34 int fa[N];//保存dfs树的信息
 35 int level[N];//记录节点在dfs树中的深度
 36 int bridge[N];//记录割边,若bridge[u] == 1, 则<u, fa[u]>为一条割边
 37
 38 void tarjan(int u, int father){
 39     fa[u] = father;
 40     dfn[u] = low[u] = deep++;
 41     level[u] = level[father]+1;
 42     for(int i = head[u]; i != -1; i = edge[i].next){
 43         int v = edge[i].to;
 44         if(dfn[v] == -1){
 45             tarjan(v, u);
 46             low[u] = min(low[u], low[v]);
 47             if(low[v] > dfn[u]){
 48                 bridge[v] = 1;
 49                 ans++;
 50             }
 51         }else if(v != father)
 52               low[u] = min(low[u], dfn[v]);
 53     }
 54 }
 55
 56 void lca(int a, int b){
 57     while(level[a] > level[b]){
 58         if(bridge[a]){
 59             ans--;
 60             bridge[a] = 0;
 61         }
 62         a = fa[a];
 63     }
 64     while(level[b] > level[a]){
 65         if(bridge[b]){
 66             ans--;
 67             bridge[b] = 0;
 68         }
 69         b = fa[b];
 70     }
 71     while(a != b){
 72         if(bridge[a]){
 73             ans--;
 74             bridge[a] = 0;
 75         }
 76         if(bridge[b]){
 77             ans--;
 78             bridge[b] = 0;
 79         }
 80         a = fa[a];
 81         b = fa[b];
 82     }
 83 }
 84
 85 int main()
 86 {
 87     //freopen("inputD.txt", "r", stdin);
 88     int kase = 0;
 89     while(scanf("%d%d", &n, &m)!=EOF && (n || m)){
 90         printf("Case %d:\n", ++kase);
 91         init();
 92         int u, v;
 93         for(int i = 0; i < m; i++){
 94             scanf("%d%d", &u, &v);
 95             add_edge(u, v);
 96         }
 97         memset(bridge, 0, sizeof(bridge));
 98         memset(dfn, -1, sizeof(dfn));
 99         memset(low, 0, sizeof(low));
100         level[0] = 0;
101         deep = 0;
102         tarjan(1, 0);
103         int q;
104         scanf("%d", &q);
105         while(q--){
106             scanf("%d%d", &u, &v);
107             if(ans)lca(u, v);
108             printf("%d\n", ans);
109         }
110         printf("\n");
111     }
112
113     return 0;
114 }
时间: 2024-10-29 04:21:03

POJ3694(KB9-D 割边+LCA)的相关文章

POJ3694 Network 割边+LCA

题目链接: Poj3694 题意: 给出一个N(1 ≤ N ≤ 100,000)个点 和 M(N - 1 ≤ M ≤ 200,000)的连通图. 有Q ( 1 ≤ Q ≤ 1,000)个询问 每次询问增加一条边(累加下去) 输出每增加一条边后剩下的桥的数量 题解: 10W点加1000次询问 每次询问都用Tarjin算法求一次肯定会超时的 考虑  每次加一条边a-b的实质: 从a到b的路径中的所有割边都将消失 那如何记录这条路径呢 在Tarjan算法递归的过程中通过树边建立一棵树 然后每次询问分别

POJ3694 Network(连通图+LCA)

题目链接:http://poj.org/problem?id=3694 题目大意:给定一个图,每次添加一条边(可能有重边).输出每次添加后桥的 数目.由于添加边的次数比较多,添加一次Tarjin一次明显会超时.后来查到了 LCA算法,利用保存的子节点与最近父节点的关系进行计算的.第一次Tarjin后将 桥和其所在的父子节点关系保存下来,之后的m次添加边只需要在LCA中判断添加 的边是否为桥,若为桥则将此桥标记抹去,并将桥数减一,否则无影响. 附AC代码: #include <stdio.h>

hdu2460 poj3694 求桥 + 求lca

http://poj.org/problem?id=3694 题意: 给定一个图,对这个图进行加边,求出每加一条边后,图中桥的个数. 思路: 首先肯定是要先求出原图中桥的个数,并且把桥标记起来.思考加一条边以后桥的数量会减少多少,联想到之前的那道题,就是加一条边,能够使桥的数量最少是多少.之前那个做法就是缩点后树的直径,这个就是可以减少的最多的桥的数量.因为如果这是一条链,将两个端点连起来,这上面的桥都消失了.. 所以按照这个思路,可以考虑,对于每个要加的边,求出他们的lca,在这个路径上如果碰

[POJ3694]Network(LCA, 割边, 桥)

题目链接:http://poj.org/problem?id=3694 题意:给一张图,每次加一条边,问割边数量. tarjan先找出所有割边,并且记录每个点的父亲和来自于哪一条边,然后询问的时候从两个点向上找lca,沿途更新割边数量和割边状态即可. AC代码 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 11 ┓

hdu2460&amp;&amp;poj3694 缩点+lca变形

http://acm.hdu.edu.cn/showproblem.php?pid=2460 http://poj.org/problem?id=3694 Problem 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 are c

[hdu2460]network(依次连边并询问图中割边数量) tarjan边双联通分量+lca

题意: 给定一个n个点m条边的无向图,q个操作,每个操作给(x,y)连边并询问此时图中的割边有多少条.(连上的边会一直存在) n<=1e5,m<=2*10^5,q<=1e3,多组数据. 题解: 用tarjan求边双连通分量并缩点,缩点后组成一棵树,记录此时割边共有sum条. 连接(x,y),设c[i]为缩点后i所在的新点(边双连通分量),则c[x]-->lca-->c[y]形成一个环,环上的所有边都不再是割边,走一遍并标记,如果遇到没标记过的就sum--. 1 #includ

POJ3694 Network(Tarjan双联通分图 LCA 桥)

链接:http://poj.org/problem?id=3694 题意:给定一个有向连通图,每次增加一条边,求剩下的桥的数量. 思路: 给定一个无向连通图,添加一条u->v的边,求此边对图剩余的桥的数量的影响:     若u,v在同一个强联通分量中,则是否添加无影响.否则从u,v的LCA到u,v的边上所有的桥都不再是桥.     在Tarjan算法中,对在同一个强联通分量中的点使用并查集合并,实现缩点,同时记录父亲节点.若u,v属于不同的强连通分量,将dfn较大的点(设为v)向上合并直到dfn

poj3694(强连通缩点+lca)

传送门:Network 题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥. 分析:方法(1219ms):用并查集缩点,把不是桥的点缩成一个点,然后全图都是桥,每次加边的两个点如果是缩后的同个点,必定不是桥,否则是桥,再把它们到达lca之间的点缩成一点. 方法2(A巨思路360ms):先一次tarjan缩点,重新建图得到一颗树,每次加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计

poj3694(lca + tarjan求桥模板)

题目链接: http://poj.org/problem?id=3694 题意: 给出一个 n 个节点 m 条边的图, 然后有 q 组形如 x, y 的询问, 在前面的基础上连接边 x, y, 输出当前图中有多少桥 . 思路: http://www.cnblogs.com/scau20110726/archive/2013/05/29/3106073.html 代码: 1 #include <iostream> 2 #include <stdio.h> 3 #include <