POJ3694 Network(边双连通+LCA)

题意:给一个n顶点m条边的无向图,有若干条桥,现在有q个询问,每次询问在这个图里面添加一条边,问添加这条边之后剩下的桥的数目有多少

思路:百度了很久题解..主要是丝毫不会LCA..做法就是先求出图中的桥和双连通分量,缩点(这里不用真的缩点,其实DFS留下的low和pre数组,记录每个点的父节点就能形成一颗深搜树,只要在出桥的时候标记一下然后LCA的时候利用pre数组就可以,因为u和v的最近公共祖先pre一定相同),树上的肯定都是桥,那么如果X和Y在同一个分量中就对桥边数毫无影响,如果是不同的缩点,那么连接起来之后,u到LCA到v这个环里面的桥都要删除,向上找它们的LCA,因为它们之间连了一条边,所以这些点到它们的LCA之间的边都不是割边了,找LCA时,先将两点上升到同一层次,然后一起再向上找父亲节点,其间遇到桥就把桥的标记删除,并且答案减1。


#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 100005
#define maxm 100000+10
#define LL long long
int cas=1,T;
int n,m;
int sum = 0;
int dfs_clock;            //时钟,每访问一个结点增1
vector<int>G[maxn];       //图
int cut;                 //记录桥数
int bridge[maxn];
int father[maxn]; 
int pre[maxn];            //pre[i]表示i结点被第一次访问到的时间戳,若pre[i]==0表示还未被访问
int low[maxn];            //low[i]表示i结点及其后代能通过反向边连回的最早的祖先的pre值
//bool iscut[maxn];         //标记i结点是不是一个割点
//int cut[maxn];            //切割这个结点后的儿子数
//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割点和桥
//初始调用dfs(root,-1)
int dfs(int u,int fa)
{
	int flag = 0;
	int lowu=pre[u]=++dfs_clock;
	int child = 0;                //子结点数目
	for (int i = 0;i<G[u].size();i++)
	{
		int v = G[u][i];
		if (v==fa && !flag)
		{
			flag++;
			continue;
		}
		if (!pre[v])
		{
			child++;              //未访问过的结点才能算是u的孩子
			int lowv = dfs(v,u);
			father[v]=u;            //记录v的父亲
			lowu = min(lowu,lowv);
			if (lowv>pre[u])
			{
				cut++;
				bridge[v]=1;
			}
			/*if (lowv >=pre[u])
			{
				iscut[u]=1;           //u是割点
				cut[u]++;
				if (lowv > pre[u])       //(u,v)边时桥
			//		printf("qiao")
			}*/
		}
		else/* if (pre[v] <pre[u] && v!=fa) */ //v!=fa确保了(u,v)是从u到v的反向边
		{
			lowu = min(lowu,pre[v]);
		}
	}
	return low[u]=lowu;
}


void init()
{
	dfs_clock = 0;
	sum=0;
	memset(pre,0,sizeof(pre));
	memset(father,0,sizeof(father));
	memset(bridge,0,sizeof(bridge));
	cut=0;
//	memset(iscut,0,sizeof(iscut));
//	memset(cut,0,sizeof(cut));
	for (int i = 0;i<=n;i++)
		G[i].clear();
}

int lca(int u,int v)
{
	int cut1=0;
	while (pre[u]>pre[v])
	{
		if (bridge[u])
		{
			cut1++;
			bridge[u]=0;
		}
		u=father[u];
	}
	while (pre[v]>pre[u])
	{
		if (bridge[v])
		{
			cut1++;
			bridge[v]=0;
		}
		v=father[v];
	}
	while (u!=v)
	{
		if (bridge[u])
		{
			bridge[u]=0;
			cut1++;
		}
		if (bridge[v])
		{
			bridge[v]=0;
			cut1++;
		}
		u=father[u];
		v=father[v];
	}
	return cut1;
}
int main()
{
	//freopen("in","r",stdin);
	while (scanf("%d%d",&n,&m)!=EOF && n)
	{
		init();
		for (int i = 0;i<m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		dfs(1,-1);
		int q;
		scanf("%d",&q);
		printf("Case %d:\n",cas++);
		while (q--)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			cut-=lca(u,v);
			printf("%d\n",cut);
		}
	}
	//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
	return 0;
}



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 andB.

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值