poj3694 边-双连通分量+lca

题意:先给了一张无向图,然后依次加边,每次求桥的数量

题解:先用一次tarjan,我们可以标记桥的位置和记录桥的数量同时记录fa数组,然后更新边的时候我们可以用lca,因为在tarjan缩点之后得到了一颗树,当连接a,b节点时,可以直观的看出从a,b的最近公共祖先到a,b之间所有的桥都会消失,我们可以不断更新桥的标记来输出答案,同时之前连的边对后面的(除了桥数以外)结果没有影响

#include<map>
#include<set>
#include<list>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;
using namespace __gnu_cxx;

const double g=10.0,eps=1e-7;
const int N=100000+10,maxn=100000+10,inf=0x3f3f3f;

struct edge{
    int to,Next;
}e[N*6];
int head[N],cnt,fa[N];
int dfn[N],low[N];
int index,num,iscut[N];
void add(int u,int v)
{
    e[cnt].to=v;
    e[cnt].Next=head[u];
    head[u]=cnt++;
    e[cnt].to=u;
    e[cnt].Next=head[v];
    head[v]=cnt++;
}
void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        dfn[i]=low[i]=iscut[i]=0;
    }
    memset(head,-1,sizeof head);
    index=num=cnt=0;
}
void tarjan(int u,int f)
{
    dfn[u]=low[u]=++index;
    int k=0;
    for(int i=head[u];~i;i=e[i].Next)
    {
        int x=e[i].to;
        if(x==f&&!k)
        {
            k++;
            continue;
        }
        if(!dfn[x])
        {
            fa[x]=u;
            tarjan(x,u);
            low[u]=min(low[u],low[x]);
            if(low[x]>dfn[u])num++,iscut[x]=1;
        }
        else low[u]=min(low[u],dfn[x]);
    }
}
void lca(int a,int b)
{
    if(dfn[a]>dfn[b])swap(a,b);
    while(dfn[a]>dfn[b])
    {
        if(iscut[a])num--;
        iscut[a]=0;
        a=fa[a];
    }
    while(a!=b)
    {
        if(iscut[a])num--;
        if(iscut[b])num--;
        iscut[a]=iscut[b]=0;
        a=fa[a];b=fa[b];
    }
}
int main()
{
    int n,m,res=1;
    while(~scanf("%d%d",&n,&m))
    {
        if(!n&&!m)break;
        init(n);
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        fa[1]=1;
        tarjan(1,-1);
        printf("Case %d:\n",res++);
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            lca(a,b);
            printf("%d\n",num);
        }
        puts("");
    }
    return 0;
}
/************

************/
View Code

 

posted @ 2017-10-28 01:54  walfy  阅读(203)  评论(0编辑  收藏  举报