7_6_B题 Network题解[POJ3694] (LCA + 求桥 + 并查集)

题目链接

简单题意

给出一个无向图,然后给出一些点对,在点对之间连边,问每次连边之后图中还有多少桥。

思路

先用Tarjan算法求桥,同时用并查集缩点,把所有非桥的边缩起来,这样剩下的就是一个只包含桥的树,在每次加边的时候通过并查集,判断两点是否在缩起来的点中,如果是则加入该边对桥的数量没有任何影响直接返回,如果不是就肯定会构成环,这是要找两者的最近公共祖先,可以通过之前的Tarjan算法遗留的dfn信息来做,两点到LCA的沿途的所有边都是新环上的边,都缩起来为下一次询问做准备,同时减去相应的桥的数量。

代码

#include 
#include 
#include 
using namespace std;

const int maxn = 1e5+5;

vector <int> G[maxn];
int dfn[maxn],low[maxn];
int fa[maxn];
int pre[maxn];
int bricnt = 0,times = 0;

void init(int n){
    for(int i = 0 ; i <= n ; i ++){
        G[i].clear();
        fa[i] = i;
        pre[i] = i;
    }
    bricnt = times = 0;
    memset(dfn,-1,sizeof dfn);
    memset(low,-1,sizeof low);
}

inline void addedge(int from, int to){
    G[from].push_back(to);
    G[to].push_back(from);
}

int Find(int x){
    return fa[x] == x ? fa[x]:fa[x] = Find(fa[x]);
}

bool Union(int x, int y){
    int a = Find(x);
    int b = Find(y);
    if(a==b) return false;
    fa[b] = a;
    return true;
}

inline int del(int x){
    if(Union(pre[x],x)) bricnt --;
    return pre[x];
}

int Lca(int u,int v){
    if(Find(u) == Find(v))
        return bricnt;
    if(dfn[u] > dfn[v])
        swap(u,v);
    while(dfn[u] < dfn[v])
        v = del(v);
    while(u!=v){
        u = del(u);
    }
}

void Tarjan(int cur,int from){
    bool flag = true;
    dfn[cur] = low[cur] = times++;
    for(int i = 0 ; i < G[cur].size(); i ++){
        int to = G[cur][i];
        if(from == to && flag){//flag处理重边
            flag = 0;
            continue;
        }
        if(dfn[to] == -1){
            pre[to] = cur;
            Tarjan(to,cur);
            low[cur] = min(low[cur],low[to]);
            if(low[to] > dfn[cur])
                bricnt++;
            else
                Union(cur,to);
        }
        else
            low[cur] = min(low[cur], dfn[to]);
    }
}

int main(){
    int n,m,Q;
    int kas = 1;
    while(~scanf("%d %d", &n,&m),(n+m)){
        init(n);
        for(int i = 0 ; i < m ; i ++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v);
        }
        Tarjan(1,0);
        scanf("%d", &Q);
        printf("Case %d:\n",kas++);
        for(int i = 0 ; i < Q; i ++){
            int u,v;
            scanf("%d %d",&u,&v);
            Lca(u,v);
            printf("%d\n",bricnt);
        }
        puts("");
    }
    return 0;
}

你可能感兴趣的:(题解)