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

 

割邊:在連通圖中,刪除了連通圖的某條邊后,圖不再連通。這樣的邊被稱為割邊,也叫做橋。
割點:在連通圖中,刪除了連通圖的某個點以及與這個點相連的邊后,圖不再連通。這樣的點被稱為割點。
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 }

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com