codeforces 178B


题意:给一个n个点的无向图,m条双向边,保证没有重边和自环,图连通,有q个询问,给两个点,S和T,问从S到T有多少条割边。

思路:看到这题第一反应就是求双连通分量,然后缩点,因为在同一个双连通分量内肯定没有割边,然后缩点后原图就变成了一棵树,因为保证原图连通,所以得到的也只有一颗树,树中的边即为原图中的割边,于是问题就转化成求树中两点的距离了,用LCA即可解决。先贴一个代码。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
using namespace std;
struct edge
{
    int to;
    int next;
    int num;
}e[3][maxn<<2];
int box[3][maxn],cnt[3];
void init()
{
    memset(box,-1,sizeof(box));
    memset(cnt,0,sizeof(cnt));
}
void add(int from,int to,int num,int t)
{
    e[t][cnt[t]].to=to;
    e[t][cnt[t]].num=num;
    e[t][cnt[t]].next=box[t][from];
    box[t][from]=cnt[t]++;
}
int pre[maxn];
int low[maxn];
int bridge[maxn];
int bcnt=0;
int cnt0;
void bridge_search(int now,int fa)
{
    int t;
    int v,w;
    low[now]=pre[now]=++cnt0;
    for(t=box[0][now];t+1;t=e[0][t].next)
    {
        v=e[0][t].to;
        if(v==fa)
        continue;
        if(!pre[v])
        {
            bridge_search(v,now);
            if(low[v]<low[now])
            low[now]=low[v];
            if(low[v]>pre[now])
            {
                bridge[e[0][t].num]=1;
            }
        }
        else
        {
            if(low[now]>pre[v])
            low[now]=pre[v];
        }
    }
}
int Bridge(int n)
{
    int i;
    cnt0=0;
    memset(pre,0,sizeof(pre));
    memset(low,0,sizeof(low));
    memset(bridge,0,sizeof(bridge));
    bcnt=0;
    for(i=1;i<=n;i++)
    {
        if(!pre[i])
        {
            bridge_search(i,0);
        }
    }
    return bcnt;
}
int vis[maxn];
int dist[maxn];
void Dfs(int now,int num)
{
    low[now]=num;
    vis[now]=1;
    int t,v,nn;
    for(t=box[0][now];t+1;t=e[0][t].next)
    {
        v=e[0][t].to,nn=e[0][t].num;
        if(bridge[nn])
        continue;
        if(!vis[v])
        {
            Dfs(v,num);
        }
    }
}
void solve(int n)//Ëõµã
{
   int i,sum=0;
   memset(low,0,sizeof(low));
   memset(vis,0,sizeof(vis));
   for(i=1;i<=n;i++)
   {
       if(!low[i])
       Dfs(i,++sum);
   }
   for(i=1;i<=n;i++)
   {
       int t,v;
       for(t=box[0][i];t+1;t=e[0][t].next)
       {
           v=e[0][t].to;
           if(low[i]!=low[v])
           {
               add(low[i],low[v],0,1);
               add(low[v],low[i],0,1);
           }
       }
   }
}
void dfs(int now,int deep)
{
    dist[now]=deep;
    vis[now]=1;
    int t,v;
    for(t=box[1][now];t+1;t=e[1][t].next)
    {
        v=e[1][t].to;
        if(!vis[v])
        {
            dfs(v,deep+1);
        }
    }
}
int f[maxn];
void finit(int n)
{
    int i;
    for(i=0;i<=n;i++)
    f[i]=i;
}
int find(int x)
{
    if(x==f[x])
    return x;
    return f[x]=find(f[x]);
}
int ans[maxn];
void lca(int now)
{
    f[now]=now;
    vis[now]=1;
    int t,v,x;
    for(t=box[1][now];t+1;t=e[1][t].next)
    {
        v=e[1][t].to;
        if(!vis[v])
        {
            lca(v);
            f[v]=now;
        }
    }
    for(t=box[2][now];t+1;t=e[2][t].next)
    {
        v=e[2][t].to,x=e[2][t].num;
        if(vis[v]==2)
        {
            int tt=find(v);
            ans[x]=dist[now]+dist[v]-2*dist[tt];
        }
    }
    vis[now]=2;
}
int main()
{
    //freopen("dd.txt","r",stdin);
    int n,m,i,a,b,q;
    scanf("%d%d",&n,&m);
    init();
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b,i,0);
        add(b,a,i,0);
    }
    memset(ans,0,sizeof(ans));
    Bridge(n);
    solve(n);
    memset(vis,0,sizeof(vis));
    dfs(1,0);
    scanf("%d",&q);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d",&a,&b);
        if(low[a]!=low[b])
        {
            add(low[a],low[b],i,2);
            add(low[b],low[a],i,2);
        }
    }
    memset(vis,0,sizeof(vis));
    lca(1);
    for(i=1;i<=q;i++)
    printf("%d\n",ans[i]);
    return 0;
}


 

posted @ 2013-03-30 16:02  javawebsoa  Views(218)  Comments(0Edit  收藏  举报