Network
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 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条边的无向联通图。有m次询问,每次询问在上一次询问的基础上,加上一条边,求加边后,图中的桥的数量。
题解:
将双联通分量缩为一个点,缩完点后的图与桥形成树。当添加一条边时,树上两点间路径的上的所有点缩为一个点。新的树的边数即桥的数量。
可以从原始图中求一个生成树,将生成树未用到的边依次加到树中,缩点,同时维护桥的数量即可。
缩点可以利用并查集实现。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<map>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1000100;
const int mod = 10007;
int u[maxn], v[maxn], a[maxn], fa[maxn], b[maxn], dep[maxn];
vector<int> g[maxn], id[maxn];
int Find(int x);
void dfs(int u, int d);
int solve(int u, int v);
int main()
{
int n, m, i, j, k, ans, q, x, y, cas = 1;
while(scanf("%d %d", &n, &m), n||m)
{
for(i=0;i<=m+5;i++){
id[i].clear();
g[i].clear();
a[i] = 0;
b[i] = i;
dep[i] = 0;
}
ans = n-1;
for(i=0;i<m;i++){
scanf("%d %d", &u[i], &v[i]);
g[u[i]].push_back(v[i]);
g[v[i]].push_back(u[i]);
id[u[i]].push_back(i);
id[v[i]].push_back(i);
}
fa[1] = 0;
dfs(1, 1);
for(i=0;i<m;i++)
if(!a[i])ans -= solve(u[i], v[i]);
printf("Case %d:\n", cas++);
scanf("%d", &q);
while(q--)
{
scanf("%d %d", &x, &y);
ans -= solve(x, y);
printf("%d\n", ans);
}
printf("\n");
}
return 0;
}
void dfs(int u, int d)
{
dep[u] = d;
for(int i=0;i<g[u].size();i++)
if(!dep[g[u][i]]){
fa[g[u][i]] = u;
a[id[u][i]] = 1;
dfs(g[u][i], d+1);
}
}
int solve(int u, int v)
{
int ans = 0;
while(1)
{
int x = Find(u), y = Find(v);
if(x == y)break;
if(dep[x] > dep[y]){
int z = Find(fa[x]);
b[x] = z;
u = z;
}else{
int z = Find(fa[y]);
b[y] = z;
v = z;
}
ans++;
}
return ans;
}
int Find(int x)
{
return b[x]=b[x]==x?x:Find(b[x]);
}