POJ3694 Network

Network
Time Limit:5000S   Memory Limit:65536K
Total Submissions:13005   Accepted:4710

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条边的无向连通图,每次插入一条边,问插完以后图中有几个桥

思路:
不难想到先边双连通分量,然后縮点,原图就变成了有x个点,x-1条边的树,其中所有的树边都是桥
倘若每次只询问插入边后图中桥的个数,不将边插入,我们只需要一个朴素LCA即可,x到y之间的所有边都不再是桥,时间复杂度为O(M+N*Q),可以过
然而每一次要将边实际插入,这就变得有些复杂了
解法是每次每次找到一个环,用并查集将环中所有的点都指向深度最浅(即最近公共祖先),即可
其实不算特别难,只是很坑,上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
#define MAXN 100050
#define MAXM 410000
using namespace std;
int n,m,q,tot=-1;
queue<int> Q;
int to[MAXM],nxt[MAXM],fir[MAXN],power[30];
int tos[MAXM],nxts[MAXM],firs[MAXN],tots=-1,bj[MAXN];
int num,col[MAXN],cnt,flag,ans,dfn[MAXN],low[MAXN],fa[MAXN],dep[MAXN];
bool bri[MAXM];
void ade(int u,int v){
	to[++tot]=v;
	nxt[tot]=fir[u];
	fir[u]=tot;
}
void ades(int u,int v){
	tos[++tots]=v;
	nxts[tots]=firs[u];
	firs[u]=tots;
}
void init(){
	memset(bri,0,sizeof(bri));
	memset(fir,-1,sizeof(fir));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(bj,0,sizeof(bj));
	memset(col,0,sizeof(col));
	memset(firs,-1,sizeof(firs));
	memset(fa,0,sizeof(fa));
	memset(dep,0,sizeof(dep));
	tot=-1; tots=-1;
	num=0; cnt=0;
} 
void Tarjan(int x,int fa){
	dfn[x]=low[x]=++num;
	for(int k=fir[x];k!=-1;k=nxt[k]){
		if(to[k]!=fa && !dfn[to[k]]){
			Tarjan(to[k],x);
			if(low[to[k]]>dfn[x]) bri[k]=bri[k^1]=1;
			low[x]=min(low[x],low[to[k]]);
		}
		else if(to[k]!=fa) low[x]=min(low[x],dfn[to[k]]);
	}
}
void dfs(int x){
	col[x]=cnt;
	for(int k=fir[x];k!=-1;k=nxt[k]) if(!col[to[k]] && !bri[k]) dfs(to[k]);
}
void get_tree(int x){
	for(int k=firs[x];k!=-1;k=nxts[k]){
		if(!fa[tos[k]] && tos[k]!=1){
			fa[tos[k]]=x; dep[tos[k]]=dep[x]+1;
			get_tree(tos[k]);
		}
	}
}
int finds(int x){
	if(bj[x]==x) return x;
	else return bj[x]=finds(bj[x]);
}
int LCA(int x,int y){
    while(!Q.empty()) Q.pop();
	while(x!=y){
		if(dep[x]<dep[y]) swap(x,y);
		while(dep[x]>=dep[y] && x!=y) Q.push(x),x=finds(bj[fa[x]]);
	}
	if(x==y) return x;
}
int main(){
	power[0]=1;
	rep(i,1,25) power[i]=power[i-1]*2;
	while(scanf("%d%d",&n,&m) && n){
	    init();
		rep(i,1,m){
			int a,b;scanf("%d%d",&a,&b);
			ade(a,b);ade(b,a);
		}
		Tarjan(1,-1);
		++flag;
		rep(i,1,n) if(!col[i]) ++cnt,dfs(i); ans=cnt;
		rep(i,1,n){
			for(int k=fir[i];k!=-1;k=nxt[k]){
				if(col[i]!=col[to[k]]) ades(col[i],col[to[k]]);
			}
		}
		dep[1]=1; fa[1]=0; get_tree(1);
		rep(i,1,cnt) bj[i]=i;
		scanf("%d",&q);
		printf("Case %d:
",flag);
		rep(i,1,q){
			int a,b,c;
			scanf("%d%d",&a,&b);
			if(finds(bj[col[a]])==finds(bj[col[b]])){
				printf("%d
",ans-1);
			    continue;
			}
			c=LCA(finds(bj[col[a]]),finds(bj[col[b]]));
			while(!Q.empty()) bj[Q.front()]=bj[c],Q.pop(),ans--;
			printf("%d
",ans-1);
		}
		printf("
");
	}
}

  

 
原文地址:https://www.cnblogs.com/handsome-zlk/p/10180816.html