tarjan算法(四)

关于tarjan算法已经写了三篇了,每一次刷题,写博客都感觉收获颇多啊

这一次是关于tarjan算法求解最近公共祖先,准备参照HDU 2460来介绍,但是HDU 上面这题的数据很水,还请各位刷题的同学多多留意

在一次深搜之后我们已经有了各个点的dfn,现在给你两个点u,v,对于这两个点,如果dfn[u]>dfn[v]说明u比v提前搜索到了,那么从v一直查找v的上一个节点,最终达到一个点p,dfn[p]<=u;很容易知道p就是u,v的最近公共祖先。因为在搜索完u所在的搜索树之后,会回溯到p点,然后继续搜索以p为根的其他搜索树,此时其他搜索树上节点的时间戳都要大于u,所以在从v往前查询时的第一个dfn小于dfn[u]的点就是他们的公共祖先······不知道说的清不清楚,不明白的话稍微画个图就行了

下面贴题:

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

题目大意:给你一个连通图,里面有一些桥,现在要加入一些新的边,求出每加入一个新的边时,还有多少个桥

题解:先用tarjan算法求出所有的桥,然后每加入新的边,找出他们到其最进公共祖先上有多少桥,全部的桥的数量减去这些桥的数量就是结果

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 100005
#define Maxm 400005
int dfn[Maxn];
int low[Maxn];
int vis[Maxn];
int fa[Maxn];

int head[Maxn];
int u[Maxm];
int v[Maxm];
int _next[Maxm];

int num;
int ans;
int cnt;
void dfs(int k){
	dfn[k]=low[k]=num++;
	int flag=0;
	for(int i=head[k];i!=-1;i=_next[i]){
		int e=v[i];
		if(!dfn[e]){
			fa[e]=k;
			dfs(e);
			low[k]=min(low[e],low[k]);
		}
		else if(e==fa[k]&&!flag) {
			flag=1;
			continue;
		}
		else low[k]=min(low[k],dfn[e]);
	}
	if(low[k]>dfn[fa[k]]) {
		vis[k]=1;
		ans++;
	}
}

void add(int a,int b){
	u[cnt]=a;
	v[cnt]=b;
	_next[cnt]=head[a];
	head[a]=cnt++;
}

void lca(int u,int v){
	if(dfn[u]>dfn[v]){
		u=u^v;
		v=u^v;
		u=u^v;
	}
	while(dfn[v]>dfn[u]){
		if(vis[v]) {
			vis[v]=0;
			ans--;
		}
		v=fa[v];
	}
	while(dfn[u]>dfn[v]){
		if(vis[u]) {
			vis[u]=0;
			ans--;
		}
		u=fa[u];
	}
}

int main(){
	int m,n,q;
	int tt=1;
	while(scanf("%d%d",&n,&m)){
		if(m==0&&n==0) break;
		memset(dfn,0,sizeof(dfn));
		memset(vis,0,sizeof(vis));
		memset(head,-1,sizeof(head));
		for(int i=0;i<=n;i++) fa[i]=i;
		ans=0;
		cnt=0;
		num=0;
		for(int i=0;i<m;i++){
			int s,t;
			scanf("%d%d",&s,&t);
			add(s,t);
			add(t,s);
		} 
		for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
		scanf("%d",&q);
		printf("Case %d:\n",tt++);
		for(int i=0;i<q;i++){
			int s,t;
			scanf("%d%d",&s,&t);
			lca(s,t);
			printf("%d\n",ans);
		}
		printf("\n");
	}
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值