Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 9386 | Accepted: 3496 |
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
今天做了训练计划中双联通分量的第二题,算是又一步深刻理解了LCA和深搜函数的运用,不得不说大白书上写的深搜函数要比很多博客上要好用的多,效率高也比较简单,深搜函数最终要的作用就是可以给点建立一棵深搜树,然后根据时间戳就可以判断找到割顶和桥(割边)了。
然后说一说这个题:
大意:
给你n个点和m条边,然后会有q次添加边,问你添加上当前边之后,剩下的桥的个数是多少。
思路:
对于每条添加的边(u,v),设u,v的最近公共祖先是c,那么桥数就会减少u~c的路径上的桥数+v~c的路径上的桥数,读者可以自己画图想一想为什么会是这样的。
这样我们就可以深搜一次的过程中找出桥,顺便记录搜索时每个结点的祖先。
具体的找最近公共祖先以及在路径上找桥的函数看代码吧。
另外在别的博客上看到的这个函数一直都搞不懂,因为觉得那根本是错的,然而却都能A掉这道题......不知道数据有多水。
当然我这个是按照自己画图得来的,也能A掉。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
const int MAXN=100000+5;
int n,m;
bool bridge[MAXN];
int pre[MAXN],dfn[MAXN];
int dfs_colock,bcc_cnt;
typedef vector<int>ve;//黑科技ヾ(o◕∀◕)ノヾ效率会变高,会变得多高呢自己试试吧
vector<ve>G(MAXN);
int dfs(int u,int fa)
{
int lowu=dfn[u]=++dfs_colock;
for(int i=0,l=G[u].size(); i<l; ++i)
{
int v=G[u][i];
if(!dfn[v])
{
int lowv=dfs(v,u);
pre[v]=u;
lowu=min(lowu,lowv);
if(lowv>dfn[u])
{
bcc_cnt++;
bridge[v]=1;
}
}
else if(dfn[u]>dfn[v]&&v!=fa)
{
lowu=min(lowu,dfn[v]);
}
}
return lowu;
}
void find_bcc()
{
int i;
for(i=0; i<n; ++i)
{
pre[i]=i;
dfn[i]=0;
bridge[i]=0;
}
bcc_cnt=dfs_colock=0;
dfs(0,-1);
}
int judge(int u,int v)
{
int sum=0;
while(u!=v)
{
while(dfn[u]>dfn[v])
{
if(bridge[u])
{
sum++;
bridge[u]=0;
}
u=pre[u];
}
while(dfn[v]>dfn[u])
{
if(bridge[v])
{
sum++;
bridge[v]=0;
}
v=pre[v];
}
}
return sum;
}
int main()
{
int i,ca=0;
while(~scanf("%d%d",&n,&m))
{
if(!n&&!m)break;
ca++;
for(i=0; i<n; ++i)
{
G[i].clear();
}
int u,v,q;
while(m--)
{
scanf("%d%d",&u,&v);
u--;
v--;
G[u].push_back(v);
G[v].push_back(u);
}
find_bcc();
scanf("%d",&q);
printf("Case %d:\n",ca);
while(q--)
{
scanf("%d%d",&u,&v);
u--;
v--;
bcc_cnt-=judge(u,v);
printf("%d\n",bcc_cnt);
}
puts("");
}
return 0;
}