POJ 3694 边双连通分量+LCA

Network

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 6837   Accepted: 2435

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

题目意思:给一个n个结点m条边的无向图,下面Q个操作,每个操作为x,y即在点x和y之间连一条边,每操作一次就输出该图的桥的个数。

思路:画了一下图发现,当x和y之间连边的时候,x->lca(x,y)->y路径上的所有的桥都不是桥了(桥不会增加只会减少或不变),所以思路就有了:先trajan求出所有的桥标记一下,然后每次对x,y添边的时候就找他们的最近公共祖先,把路径上的桥的标记改成不是桥的标记,桥的数目--。由于时限5000MS,所以这样虽然暴力但是还是能过得。

代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <vector>
 6 #include <queue>
 7 using namespace std;
 8
 9 #define N 100005
10
11 vector<int>ve[N];
12 int low[N], dfn[N], dfn_clock;
13 int father[N], dep[N], bridge[N], b_num;
14 int n, m;
15
16 void init(){
17     for(int i=0;i<=n;i++){
18         ve[i].clear();
19     }
20     memset(low,0,sizeof(low));
21     memset(dfn,0,sizeof(dfn));
22     memset(dep,0,sizeof(dep));
23     memset(bridge,0,sizeof(bridge));
24 }
25
26 void tarjan(int u,int fa,int d){
27     dep[u]=d;
28     father[u]=fa;
29     int i, j, k, v;
30     low[u]=dfn[u]=++dfn_clock;
31     for(i=0;i<ve[u].size();i++){
32         v=ve[u][i];
33         if(v==fa) continue;
34         if(!dfn[v]){
35             tarjan(v,u,d+1);
36             low[u]=min(low[u],low[v]);
37             if(low[v]>dfn[u]){
38                 bridge[v]=1;
39                 ++b_num;
40             }
41         }
42         else low[u]=min(low[u],dfn[v]);
43     }
44 }
45
46 void lca(int x,int y){
47     if(dep[x]<dep[y]) swap(x,y);
48     while(dep[x]>dep[y]){
49         if(bridge[x]){
50              --b_num;bridge[x]=0;
51         }
52         x=father[x];
53     }
54     while(x!=y){
55         if(bridge[x]){
56             --b_num;bridge[x]=0;
57         }
58         if(bridge[y]){
59             --b_num;bridge[y]=0;
60         }
61         x=father[x];y=father[y];
62     }
63 }
64
65 main()
66 {
67     int i, j, k, x, y, q, kase=1;;
68     while(scanf("%d %d",&n,&m)==2&&(n+m)){
69         init();
70         while(m--){
71             scanf("%d %d",&x,&y);
72             ve[x].push_back(y);ve[y].push_back(x);
73         }
74         b_num=dfn_clock=0;
75             tarjan(1,1,1);
76         scanf("%d",&q);
77         printf("Case %d:\n",kase++);
78     //    printf("b_num==%d\n",b_num);
79         while(q--){
80             scanf("%d %d",&x,&y);
81             lca(x,y);
82             printf("%d\n",b_num);
83         }
84     }
85 }
时间: 2024-08-07 08:45:21

POJ 3694 边双连通分量+LCA的相关文章

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

本文转载自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在阅读本文之前,请确保您已经理解并掌握了基本的Tarjan算法,不会的请到http://hi.baidu.com/lydrainbowcat/blog/item/42a6862489c98820c89559f3.html阅读.   基本概念:   1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最小割边集合中的边数.

连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(最近公共祖先)

PS:摘自一不知名的来自大神. 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b

poj 3694 Network(桥+lca)

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

poj 3694 无向图求桥+lca

题意抽象为: 给一个无向图和一些询问 对于每一次询问: 每次询问都会在图上增加一条边 对于每一次询问输出此时图上桥的个数. 桥的定义:删除该边后原图变为多个连通块. 数据规模:点数N(1 ≤ N ≤ 100,000) ,边数M(N - 1 ≤ M ≤ 200,000),询问数Q ( 1 ≤ Q ≤ 1,000) 先跑一遍tarjan,对边双连通分枝缩一下点. 再维护lca即可. AC代码: #include<cstdio> #include<cstring> #include<

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求桥】

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