码迷,mamicode.com
首页 > Web开发 > 详细

poj 3694 Network

时间:2018-04-01 00:00:04      阅读:277      评论:0      收藏:0      [点我收藏+]

标签:add   16px   ==   style   mes   log   void   ems   直接   

Description:

  给定一张n节点m条边的无向图,执行Q次操作,每次加一条无向边,询问当前桥的数量

 

思路:先双联通缩点,然后得到一棵树,对(x,y)连边的时候暴力LCA一下 然后将路径上的点用并查集全都压到LCA上,这样的话下次再搜到被压了的点就可以直接跳到LCA上了,向上压点的同时减去边的数量

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 100050;
const int M = 200050;

int head[N],now;
struct edges{
    int  to,next;
}edge[M<<1];
void add(int u,int v){ edge[++now] = {v,head[u]}; head[u] = now;}

int n,m,low[N],dfn[N],tot,cnt,fa[N],pre[N],dep[N],dict[N],ans;
bool bridge[M<<1];
struct input{
    int x,y;
}inp[M];

void init(){
    for(int i = 1; i <= n; i++)  fa[i] = i;
    memset(inp,0,sizeof(inp));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));  cnt = tot = 0;
    memset(pre,0,sizeof(pre));
    memset(bridge,0,sizeof(bridge));
    memset(head,0,sizeof(head));
    memset(edge,0,sizeof(edge));   now = 1;
    memset(dep,0,sizeof(dep));
    memset(dict,0,sizeof(dict));
}

void tarjan(int x,int in_edge){  //边-双联通分量缩点 
    low[x] = dfn[x] = ++cnt;
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(!dfn[v]){
            tarjan(v,i);
            low[x] = min(low[x],low[v]);
            if(low[v] > dfn[x])
              bridge[i] = bridge[i ^ 1] = 1;
        }
        else if(i != (in_edge ^ 1))
          low[x] = min(low[x],dfn[v]);
    }
    return ;
}

void dfs(int x){
    dict[x] = tot;
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(dict[v] || bridge[i]) continue;
        dfs(v);
    }
    return ;
}

void new_dfs(int x){
    for(int i = head[x]; i; i = edge[i].next){
        int v = edge[i].to;
        if(pre[x] == v) continue;
        dep[v] = dep[x] + 1;
        pre[v] = x;
        new_dfs(v);
    }
}

int get(int x){
    if(x != fa[x]) return fa[x] = get(fa[x]);
    return x;
} 

int lca(int u,int v){
    while(u != v){
        if(dep[u] > dep[v])
          u = pre[u];
        else if(dep[u] < dep[v])
          v = pre[v];
        else{
            u = pre[u];
            v = pre[v];
        }
        u = get(u),v = get(v);
    }
    return u;
}

int main(){
//    freopen("data.out","r",stdin); 
    int kase = 0, q;
    while(scanf("%d%d",&n,&m)!= EOF && n + m){
        init();
        int x,y;
        for(int i = 1; i <= m ; i++){
            scanf("%d%d",&x,&y);
            inp[i] = {x,y};
            add(x,y);  add(y,x);
        }
        tarjan(1,0);
        for(int i = 1; i <= n; i++)
          if(!dict[i]) tot++, dfs(i);
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));  now = 0;
        for(int i = 1; i <= m; i++)  //缩点后得到新图 
          if(dict[inp[i].x] != dict[inp[i].y])
            add(dict[inp[i].x],dict[inp[i].y]),add(dict[inp[i].y],dict[inp[i].x]);
        new_dfs(1);//记录每个点的父节点 
        scanf("%d",&q);
        printf("Case %d:\n",++kase);
        ans = tot - 1;
        while(q--){
            scanf("%d%d",&x,&y);
            x = get(dict[x]), y = get(dict[y]);
            int tmp = lca(x,y);
            while(x != tmp){  //将x的所有没有压到xy的LCA的点全都压到LCA上 
                ans--;
                fa[x] = tmp;
                x = get(pre[x]);
            }
            while(y != tmp){  //同上 
                ans--;
                fa[y] = tmp;
                y = get(pre[y]);
            }
            printf("%d\n",ans);
        }
        puts("");
    }
    return 0;
}

 

poj 3694 Network

标签:add   16px   ==   style   mes   log   void   ems   直接   

原文地址:https://www.cnblogs.com/Rorshach/p/8684657.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!