POJ3694:Network(並查集+縮點+lca)


Network

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 13172   Accepted: 4774

題目鏈接:http://poj.org/problem?id=3694

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

題意:

首先給出一個無向圖,然后不斷加邊,每次加一條邊就輸出當前圖中橋有多少個。

 

題解:

首先單獨計算橋很容易,但這個加邊操作有點煩人,不可能每次加條邊就求次橋吧。然后我們主要想的就是新邊和原圖的關系。

因為原圖是連通的,在原圖中,我們很容易把橋求出來,並且將相應的點進行縮點(這里我用的並查集),最后的圖中的邊都為橋,且無向圖變成了樹。

那么每次新加入一條邊,如果它連接的為不在一個集合中的點,那么必然會影響到從u到v簡單路徑上面的橋;否則就不影響。

下面關鍵就是求這個簡單路徑,由於這個題數據量較小,用個朴素的lca就行了,這里的lca沒有用深度來,而是根據dfn,很好地利用了時間戳。

代碼如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 1e5+5,M  = 2e5+5;
int n,m,ans;
int head[N];
struct Edge{
    int u,v,next;
}e[M<<1];
int T,tot;
int dfn[N],low[N],cut[N],f[N],pa[N];
void adde(int u,int v){
    e[tot].u=u;e[tot].v=v;e[tot].next=head[u];head[u]=tot++;
}
void init(){
    T=0;tot=0;ans=0;
    memset(head,-1,sizeof(head));
    memset(cut,0,sizeof(cut));
    memset(dfn,0,sizeof(dfn));
    memset(pa,0,sizeof(pa));
    for(int i=0;i<=n;i++) f[i]=i;
}
int find(int x){
    return f[x]==x ? x : f[x]=find(f[x]);
}
void Union(int u,int v){
    int fx=find(u),fy=find(v);
    if(fx!=fy) f[fx]=fy;
    return ;
}
void Tarjan(int u,int pre){
    dfn[u]=low[u]=++T;
    int son=0;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==pre) continue ;
        if(!dfn[v]){
            pa[v]=u;
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]){
                cut[v]=1;
                ans++;
            }else Union(u,v);
        }else{
            low[u]=min(low[u],dfn[v]);
        }
    }
}
int lca(int u,int v){
    if(dfn[u]<dfn[v]) swap(u,v);
    while(dfn[u]>dfn[v]){
        int fx=find(u),fy=find(pa[u]);
        if(fx!=fy){
            ans--;
            f[fx]=fy;
        }
        u=pa[u];
    }
    while(dfn[v]>dfn[u]){
        int fx=find(v),fy=find(pa[v]);
        if(fx!=fy){
            ans--;
            f[fx]=fy;
        }
        v=pa[v];
    }
    return ans ;
}
int main(){
    int cnt = 0;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n+m<=0) break ;
        cnt++;
        init();
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            adde(u,v);adde(v,u);
        }
        Tarjan(1,-1);
        int q;
        printf("Case %d:\n",cnt);
        scanf("%d",&q);
        while(q--){
            int u,v;
            scanf("%d%d",&u,&v);
            printf("%d\n",lca(u,v));
        }
    }
    return 0;
}

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: