poj3694(tarjan缩点+lca)

 

 传送门:Network

题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥。

分析:方法(1219ms):用并查集缩点,把不是桥的点缩成一个点,然后全图都是桥,每次加边的两个点如果是缩后的同个点,必定不是桥,否则是桥,再把它们到达lca之间的点缩成一点。

        方法2(A巨思路360ms):先一次tarjan缩点,重新建图得到一颗树,每次加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计时,会遇到某些边在之前就不是桥的情况,我们用并查集来跳过这些边(每一次加边就把lca路径上的点都合并到一个集合里去,这里根用最上面的点,到时如果遇到这种点,直接可以跳到它们的根上去)

方法1:

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-6

#define N 100010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

#define PII pair<int,int>

using namespace std;

struct edge

{

    int v,next;

    edge(){}

    edge(int v,int next):v(v),next(next){}

}e[N<<2];

int n,step,top,tot,num;

int head[N],dfn[N],low[N],Stack[N];

bool instack[N],vis[N<<2];

int pre[N],fa[N];

void init()

{

    tot=0;step=0;top=0;num=0;

    FILL(head,-1);FILL(dfn,0);

    FILL(low,0);FILL(instack,false);

    FILL(pre,0);FILL(vis,0);

}

void addedge(int u,int v)

{

    e[tot]=edge(v,head[u]);

    head[u]=tot++;

}

int find(int x)

{

    return fa[x]==x?x:fa[x]=find(fa[x]);

}

int merge(int x,int y)

{

    int a=find(x);

    int b=find(y);

    if(a!=b)

    {

        fa[b]=a;return 1;

    }

    return 0;

}

void tarjan(int u)

{

    dfn[u]=low[u]=++step;

    Stack[top++]=u;

    instack[u]=true;

    for(int i=head[u];~i;i=e[i].next)

    {

        int v=e[i].v;

        if(vis[i])continue;

        vis[i]=vis[i^1]=1;

        if(!dfn[v])

        {

            tarjan(v);

            pre[v]=u;

            if(low[u]>low[v])low[u]=low[v];

            //桥:一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS[u]<Low[v]

            if(low[v]>dfn[u])

            {

                num++;

            }

            else merge(u,v);

        }

        else if(low[u]>dfn[v])

        {

            low[u]=dfn[v];

        }

    }

    instack[u]=false;

    top--;

}

void lca(int a,int b)

{

    while(a!=b)

    {

        while(dfn[a]>=dfn[b]&&a!=b)

        {

            if(merge(a,pre[a]))num--;

            a=pre[a];

        }

        while(dfn[a]<=dfn[b]&&a!=b)

        {

            if(merge(b,pre[b]))num--;

            b=pre[b];

        }

    }

}

void solve()

{

    for(int i=1;i<=n;i++)

        if(!dfn[i])tarjan(i);

    int q,u,v;

    scanf("%d",&q);

    while(q--)

    {

        scanf("%d%d",&u,&v);

        lca(u,v);

        printf("%d\n",num);

    }

    puts("");

}

int main()

{

    int m,u,v,cas=1;

    while(scanf("%d%d",&n,&m)&&(n||m))

    {

        init();

        for(int i=1;i<=n;i++)fa[i]=i;

        for(int i=1;i<=m;i++)

        {

            int u,v;

            scanf("%d%d",&u,&v);

            addedge(u,v);

            addedge(v,u);

        }

        printf("Case %d:\n",cas++);

        solve();

    }

}
View Code

方法2:

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-6

#define N 100010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

#define PII pair<int,int>

using namespace std;

struct edge

{

    int v,next;

    edge(){}

    edge(int v,int next):v(v),next(next){}

}e1[N<<2],e2[N<<2];

int n,scc,step,top,tot1,tot2;

int head1[N],head2[N],dfn[N],low[N],belong[N],Stack[N];

int deep[N],fa[N],pre[N];

bool instack[N],vis[N<<2];

void init()

{

    tot1=0;tot2=0;step=0;scc=0;top=0;

    FILL(head1,-1);FILL(head2,-1);

    FILL(low,0);FILL(dfn,0);

    FILL(instack,false);FILL(vis,0);

}

void addedge1(int u,int v)

{

    e1[tot1]=edge(v,head1[u]);

    head1[u]=tot1++;

}

void addedge2(int u,int v)

{

    e2[tot2]=edge(v,head2[u]);

    head2[u]=tot2++;

}

void tarjan(int u)

{

    int v;

    dfn[u]=low[u]=++step;

    Stack[top++]=u;

    instack[u]=true;

    for(int i=head1[u];~i;i=e1[i].next)

    {

        v=e1[i].v;

        if(vis[i])continue;

        vis[i]=vis[i^1]=1;

        if(!dfn[v])

        {

            tarjan(v);

            low[u]=min(low[u],low[v]);

        }

        else if(instack[v])

        {

            low[u]=min(low[u],dfn[v]);

        }

    }

    if(dfn[u]==low[u])

    {

        scc++;

        do

        {

            v=Stack[--top];

            instack[v]=false;

            belong[v]=scc;

        }while(v!=u);

    }

}

void dfs_dep(int u,int f,int dep)

{

    pre[u]=f;deep[u]=dep;

    for(int i=head2[u];~i;i=e2[i].next)

    {

        int v=e2[i].v;

        if(v==f)continue;

        dfs_dep(v,u,dep+1);

    }

}

int find(int x)

{

    return fa[x]==x?x:fa[x]=find(fa[x]);

}

int LCA(int u,int v)

{

    while(u!=v)

    {

        if(deep[u]>=deep[v]&&u!=v)

        {

            u=pre[u];

        }

        if(deep[v]>=deep[u]&&u!=v)

        {

            v=pre[v];

        }

        u=find(u);

        v=find(v);

    }

    return u;

}

void solve()

{

    for(int i=1;i<=n;i++)

        if(!dfn[i])tarjan(i);

    for(int u=1;u<=n;u++)

    {

        for(int i=head1[u];~i;i=e1[i].next)

        {

            int v=e1[i].v;

            if(belong[v]!=belong[u])

            {

                addedge2(belong[u],belong[v]);

            }

        }

    }

    dfs_dep(1,1,0);

    for(int i=1;i<=scc;i++)fa[i]=i;

    int ans=scc-1,q,u,v;

    scanf("%d",&q);

    while(q--)

    {

        scanf("%d%d",&u,&v);

        int a=find(belong[u]);

        int b=find(belong[v]);

        int lca=LCA(a,b);

        while(a!=b)

        {

            if(deep[a]>=deep[b]&&a!=b)

            {

                ans--;

                fa[a]=lca;

                a=pre[a];

            }

            if(deep[b]>=deep[a]&&a!=b)

            {

                ans--;

                fa[b]=lca;

                b=pre[b];

            }

            a=find(a);

            b=find(b);

        }

        printf("%d\n",ans);

    }

}

int main()

{

    int m,u,v,cas=1;

    while(scanf("%d%d",&n,&m)&&(n||m))

    {

        init();

        for(int i=1;i<=n;i++)fa[i]=i;

        for(int i=1;i<=m;i++)

        {

            int u,v;

            scanf("%d%d",&u,&v);

            addedge1(u,v);

            addedge1(v,u);

        }

        printf("Case %d:\n",cas++);

        solve();

    }

}
View Code

 

你可能感兴趣的:(tar)