POJ3694 Network (縮點+並查集+LCA)

Network
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 10825   Accepted: 4043

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

題意:給出一個無向圖,往這張圖裏要加q條邊,問加了這條邊後,圖中有多少條橋(每次是在前一條邊的基礎上加的)


首先肯定是要縮點爲塊,縮點後,加邊就相當於在塊與塊之間加(同一個塊內加邊對橋無影響)

對於塊與塊來說,此時一定是沒有環的,我們可以把他看做一棵樹

每次加邊會使得樹上的一些點連成環,在這個環上的所有點就構成了一個邊雙連通分量,所以減少橋的數量=這個環上點的數量-1

至於樹上兩點之間的環,肯定是和LCA構成的,求一下LCA,把路上經過的點用並查集合併到一個集合裏就行了

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e5+200;
const int M=2e5+200;
int n,m,tot,first[N],dfn[N],low[N],dfs_num,col_num,st[N],vis[N],top,block[N];
int f[N],d[N],pre[N];
vector<int>mp[N];
struct edge
{
    int v,next,flag;
}e[M*2];
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].flag=0;
    e[tot].next=first[u];
    first[u]=tot++;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++dfs_num;
    st[top++]=u;
    vis[u]=1;
    int flag=0;
    for(int i=first[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(!flag&&v==fa)
        {
            flag=1;
            continue;
        }
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
                e[i].flag=e[i^1].flag=1;
        }
        else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    int v;
    if(dfn[u]==low[u])
    {
        ++col_num;
        do
        {
            v=st[--top];
            block[v]=col_num;
            vis[v]=0;
        }while(v!=u);
    }
}

void init()
{
    mem(first,-1);
    mem(d,0);
    mem(pre,0);
    mem(vis,0);
    mem(dfn,0);
    mem(low,0);
    mem(block,0);
    dfs_num=tot=col_num=0;
}
void dfs(int u,int fa)
{
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(v==fa)continue;
        pre[v]=u;
        d[v]=d[u]+1;
        dfs(v,u);
    }
}
int getf(int x)
{
    return f[x]==x?x:f[x]=getf(f[x]);
}
int mix(int x,int y)
{
    int tx=getf(x),ty=getf(y);
    if(tx!=ty)
    {
        f[tx]=ty;
        return 1;
    }
    return 0;
}
int lca(int a,int b)
{
    if(a==b)return col_num;
    if(d[a]>d[b])swap(a,b);
    int p=d[b]-d[a];
    while(p--)//深度不同,首先升到同一深度
    {
        col_num-=mix(b,pre[b]);
        b=pre[b];
    }
    if(a!=b)
    {
        while(a!=b)
        {
            col_num-=mix(a,pre[a]);
            col_num-=mix(b,pre[b]);
            a=pre[a];
            b=pre[b];
        }
    }
    return col_num-1;
}
int main()
{
    int u,v,q,kcase=0;
    while(scanf("%d%d",&n,&m)&&n+m)
    {
        init();
        for(int i=1;i<=n;i++)
            f[i]=i,mp[i].clear();

        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        tarjan(1,-1);//縮點
        for(int i=0;i<tot;i+=2)//縮點後建圖
        {
            int u=e[i].v,v=e[i^1].v;
            if(block[u]==block[v])continue;
            mp[block[u]].push_back(block[v]);
            mp[block[v]].push_back(block[u]);
        }
        pre[1]=1;
        dfs(1,-1);//求出每個塊的父節點,以及每個點的深度
        scanf("%d",&q);
        printf("Case %d:\n",++kcase);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            if(block[u]==block[v])//在同一個集合裏,橋的數量不減
                printf("%d\n",col_num-1);
            else
                printf("%d\n",lca(block[u],block[v]));
        }
        puts("");
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章