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

来源:互联网 发布:永宏plc解密软件 编辑:程序博客网 时间:2024/04/30 17:38

题目链接

简单题意

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

思路

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

代码

#include <cstdio>#include <vector>#include <cstring>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;}
0 0