poj 3694 无向图求桥+lca

Posted 缄默火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 3694 无向图求桥+lca相关的知识,希望对你有一定的参考价值。

题意抽象为:

给一个无向图和一些询问

对于每一次询问:

每次询问都会在图上增加一条边

对于每一次询问输出此时图上桥的个数。

 

桥的定义:删除该边后原图变为多个连通块。 

 

数据规模:点数N(1 ≤ N ≤ 100,000) ,边数M(N - 1 ≤ M ≤ 200,000),询问数Q ( 1 ≤ Q ≤ 1,000)

 

先跑一遍tarjan,对边双连通分枝缩一下点。

再维护lca即可。

AC代码:

#include<cstdio>
#include<cstring>
#include<queue>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int MAXV=110000;
const int MAXE=410000;
int DFN[MAXV],low[MAXV],par[MAXV],label[MAXV];
int pointer[MAXV];
int tot,cnt,m,n,Bcnt,ans;
vector<int> graph[MAXV];
struct Edge
{
    int to,next;
    bool vis;
    Edge() {}
    Edge(int b,int nxt,int flag) {to=b,next=nxt,vis=flag;}
}edge[MAXE];
inline void addedge(int a,int b)
{
    edge[tot]=Edge(b,pointer[a],0);
    pointer[a]=tot++;
    edge[tot]=Edge(a,pointer[b],0);
    pointer[b]=tot++;
}
void init()
{
    tot=0;
    cnt=0;Bcnt=0;
    memset(pointer,-1,sizeof(pointer));
    memset(label,0,sizeof(label));
    memset(DFN,0,sizeof(DFN));
}
void tarjan(int u,int pre)
{
    DFN[u]=low[u]=++cnt;
    for(int j=pointer[u];j!=-1;j=edge[j].next)
    {
        int v=edge[j].to;
        if(edge[j].vis) continue;
        edge[j].vis=edge[j^1].vis=1;
        if(!DFN[v])
        {
            par[v]=j;
            tarjan(v,u);
            if(low[v]<low[u]) low[u]=low[v];
        }
        else if(low[u]>DFN[v]) low[u]=DFN[v];
    }
}
void part(int u)
{
    label[u]=Bcnt;
    for(int j=pointer[u];j!=-1;j=edge[j].next)
    {
        int v=edge[j].to;
        if(!label[v]&&edge[j].vis) part(v);
    }
}
int dep[MAXV];
int father[MAXV],a[MAXV];
void lca_bfs(int S)
{
    rep(i,1,Bcnt) dep[i]=-1;
    queue<int>q;
    dep[S]=0;
    q.push(S);
    father[S]=S;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<graph[u].size();++i)
        {
            int v=graph[u][i];
            if(dep[v]==-1)
            {
                dep[v]=dep[u]+1;
                a[v]=1;
                father[v]=u;
                q.push(v);
            }
        }
    }
}
void lca(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    while(dep[u]<dep[v])
    {
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
    }
    while(u!=v)
    {
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
        if(a[u])
        {
            ans--;
            a[u]=0;
        }
        u=father[u];
    }
}
int main()
{
   // freopen("in.txt","r",stdin);
    int icase=0;
    while(scanf("%d%d",&n,&m)&&m&&n)
    {
        int a,b;
        init();
        rep(i,1,m)
        {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        tarjan(1,1);
        int tmp,u;
        rep(i,2,n)
        {
            tmp=par[i]^1;
            u=edge[tmp].to;
            if(DFN[u]<low[i])
            {
                edge[tmp].vis=edge[tmp^1].vis=0;
            }
        }
        rep(i,1,n)
        {
            if(!label[i])
            {
                Bcnt++;
                part(i);
            }
        }
        ans=Bcnt-1;
        rep(i,2,n)
        {
            if(!edge[par[i]].vis)
            {
                tmp=par[i]^1;
                u=edge[tmp].to;
                graph[label[u]].push_back(label[i]);
                graph[label[i]].push_back(label[u]);
            }
        }
        lca_bfs(1);
        int v,q;
        scanf("%d",&q);
        printf("Case %d:\n",++icase);
        rep(i,1,q)
        {
            scanf("%d%d",&u,&v);
            lca(label[u],label[v]);
            printf("%d\n",ans);
        }
        printf("\n");

    }
    return 0;
}

 

以上是关于poj 3694 无向图求桥+lca的主要内容,如果未能解决你的问题,请参考以下文章

poj3694 双连通分量+lca

(POJ 3694) Network 求桥个数

HDU 4738 无向图求桥

POJ 3694 Network (tarjan + LCA)

POJ3694 Network(Tarjan双联通分图 LCA 桥)

[POJ3694]Network(LCA, 割边, 桥)