poj 3694 Network 边双连通

给一幅图,若干个操作,每个操作时连接两个点,对于每个操作之后的图判断图中还有几条割边

解法

先求出最初的图中有几条割边bridge

在求的过程中顺便建立一个方向,相当于变成有向图,如果发现某条边不是割边,就利用并查集将两个点合并,也可以不合并,但是速度上就相差很多了

最后,一个联通块中的点就只以一个点为根了

还有,如果s-t是割边,就标记一下t

现在要连接两个点a,b

在找他们的LCA的时候如果发现某条边是割边就bridge--

因为需要一层层上去,遍历到从a,b到LCA的每条边,所以这个过程就直接暴力网上找了,不知还有没有什么更好的方法

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100010;
struct Edge
{
    int s,t;
    int next;
    int vis;
}edge[1000005];
int head[maxn];
int E=0;
void add_edge(int s,int t)
{
    edge[E].s=s;
    edge[E].t=t;
    edge[E].vis=0;
    edge[E].next=head[s];
    head[s]=E++;
}
int Time,N,M;
int dfn[maxn],low[maxn];
int  Top;
int bridge;
inline int min(int a,int b){return a<b?a:b;}
int f[maxn];
bool mark[maxn];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int s)
{
    int i,t;
    dfn[s]=low[s]=++Time;
    for (i=head[s];i!=-1;i=edge[i].next)
    {    
        if(edge[i].vis)continue;    
        edge[i].vis=edge[i^1].vis=1;
        t=edge[i].t;
        if (!dfn[t])
        {
            f[t]=s;
            dfs(t);
            low[s]=min(low[s],low[t]);
        }
        else low[s]=min(low[s],dfn[t]);
        if(low[t]<=dfn[s])
        {
            int x=find(t);
            int y=find(s);
            if(x!=y)    f[x]=y;
        }
        if(low[t]>dfn[s])
        {
            mark[t]=true;
            bridge++;
        }
    }
}
void SCC(int n)
{
    int i;bridge=0;f[1]=1;
    memset(mark,false,sizeof(mark));
    memset(dfn,0,sizeof(int)*(n+1));
    for(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||m))
    {
        E=0;
        memset(head,-1,sizeof(head));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,b);
            add_edge(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);
        }
        puts("");
    }
    return 0;
}



posted @ 2012-04-09 16:52  Because Of You  Views(419)  Comments(0Edit  收藏  举报