poj 3529 Network 双连通分连 动态求桥的数目 + tarjan离线算法求LCA

题意:一开始有n个点m条边,后来每次加一条边,求加上这一条边后途中有几座“桥”。

分析:双连通分量

View Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 100010
struct Edge{
    int u,v,next;
    int vis;
}edge[1000005];
int head[maxn];
int E=0;
void addedge(int u,int v){
    edge[E].u=u;edge[E].v=v;edge[E].vis=0;
    edge[E].next=head[u];head[u]=E++;
}
int Time,N,M;
int dfn[maxn],low[maxn];
int Top;
int bridge;
int f[maxn];
bool mark[maxn];
int find(int x) { return x==f[x]?x:f[x]=find(f[x]); }
void dfs(int u){
    int v;
    dfn[u]=low[u]=++Time;
    for(int i=head[u];i!=-1;i=edge[i].next){
        if(edge[i].vis) continue;
        edge[i].vis=edge[i^1].vis=1;
        v=edge[i].v;
        if(!dfn[v]){
            f[v]=u;
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else low[u]=min(low[u],dfn[v]);
        if(low[v]<=dfn[u]) {
            int x=find(v);
            int y=find(u);
            if(x!=y) f[x]=y;
        }
        if(low[v]>dfn[u]){
            mark[v]=true;
            bridge++;
        }
    }
}
void SCC(int n){
    bridge=0;f[1]=1;
    memset(mark,false,sizeof(mark));
    memset(dfn,0,sizeof(int)*(n+1));
    for(int i=1;i<=n;i++)
        if(!dfn[i]) dfs(i);
}
void LCA(int a,int b){
    if(dfn[a]<dfn[b]){
        a^=b;
        b^=a;
        a^=b;
    }
    while(dfn[a]>dfn[b]){
        if(mark[a]) { bridge--;mark[a]=false; }
        a=f[a];
    }
    while(a!=b){
        if(mark[a]) { bridge--;mark[a]=false; }
        a=f[a];
        if(mark[b]) { bridge--;mark[b]=false; }
        b=f[b];
    }
}
int main(){
    int n,m,i,q,a,b,ca=1;
    while(~scanf("%d%d",&n,&m) && n){
        E=0;
        memset(head,-1,sizeof(head));
        for(i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        SCC(n);
        printf("Case %d:\n",ca++);
        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&a,&b);
            LCA(a,b);
            printf("%d\n",bridge);
        }
        printf("\n");
    }
    return 0;
}
posted @ 2012-07-08 03:10  lenohoo  阅读(232)  评论(0编辑  收藏  举报