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;

}


 

你可能感兴趣的:(codeforces)