POJ_3694 Network Tarjin + LCA + 并查集
来源:互联网 发布:mac软件无法强制退出 编辑:程序博客网 时间:2024/04/29 22:59
http://poj.org/problem?id=3694
题意:给定一个有N个点,M条边的无向图(图原本连通),N<=10000 ,M<=20000,现在要求将Q条边逐一加入到无向图中去,要求对于每次加入边之后,输出图中的桥的条数。
思路:先对原无向图缩点,初始时候,桥的条数为:cnt -1 , 其中cnt为图中连通分量的个数,每次增加一条边的时候,我们可以先找出两个顶点的LCA,然后沿着树边往根移动,将这个圈又进行缩点,此时就可以在O(N)的时候内求出此时的桥。因为只需要求两个点之间的LCA,所有可以直接从两个结点往上找,知道找到相同的结点为止。
代码:
#include<stdio.h>#include<string.h>const int MAXN = 100010 ;const int MAXM = 200010 ;int N , M , Q ;int Gnext[MAXM*2] ;int Gv[MAXM*2] ;int Gr[MAXN], Gc ;int gnext[MAXM*2] ;int gv[MAXM*2] ;int gr[MAXN],gc ;int ans ;void init(){ memset(Gr, -1 ,sizeof(Gr)); memset(gr, -1, sizeof(gr)) ; Gc = 0 ; gc = 0 ;}void add(int a,int b){ Gv[Gc] = b ; Gnext[Gc] = Gr[a] ; Gr[a] = Gc++ ;}int dfn[MAXN] , low[MAXN] , col[MAXN] ,st[MAXN];int idx, top, cnt ;void tarjin(int x,int fa){ low[x] = dfn[x] = ++idx ; st[top++] = x ; bool f = 1 ; for(int i=Gr[x] ;i!=-1;i=Gnext[i]){ int v = Gv[i] ; if(v==fa && f){ f = 0 ; continue ; } if( dfn[v] == -1){ tarjin(v,x); if( low[v] < low[x]) low[x] = low[v] ; if( low[v] > dfn[x] ){ for( st[top]=-1 ;st[top]!=v;){ top-- ; col[ st[top] ] = cnt ; } cnt++ ; } } else if(dfn[v] < low[x]) low[x] = dfn[v] ; }}void add1(int a, int b){ gv[gc] = b ; gnext[gc] = gr[a] ; gr[a] = gc++ ;}int p[MAXN] ;void solve(){ top = idx = 0 ; cnt = 1 ; memset(dfn, -1, sizeof(dfn)) ; memset(col,0, sizeof(col)) ; for(int i=1;i<=N;i++){ if( dfn[i] == -1){ tarjin(i,-1); } } for(int i=1;i<=N;i++){ for(int j=Gr[i] ;j!=-1;j=Gnext[j]){ int u = Gv[j] ; if( col[i] != col[u] ){ add1( col[i] , col[u] ); } } } for(int i=0;i<cnt;i++){ p[i] = i ; }}int pre[MAXN] ;bool vis[MAXN] ;void build(int u,int fa){ for(int i=gr[u];i!=-1;i=gnext[i]){ int v = gv[i] ; if(v == fa) continue ; pre[v] = u ; build(v,u) ; }}void deal(int a, int b){ memset(vis, 0 ,sizeof(vis)); int aa = a ; vis[aa] = 1 ; int ac ,bc ; ac = bc = 0 ; while(pre[aa] != -1){ vis[ pre[aa] ] = 1 ; aa = pre[aa] ; } int bb = b ; int ancer = -1; if( vis[bb] == 1) ancer = bb ; else{ while( pre[bb]!=-1 && !vis[ pre[bb] ]){ bb = pre[bb] ; } if( pre[bb]!=-1 ){ ancer = pre[bb] ; } } if(ancer == -1) return ; aa = a ; while( aa != ancer){ ac ++ ; aa = pre[aa] ; } bb = b ; while( bb != ancer){ bc ++ ; bb = pre[bb] ; } ans = ans - ac - bc ; for(aa=a;aa!=ancer;aa=pre[aa]){ p[aa] = ancer ; for(int j=gr[aa] ;j!=-1;j=gnext[j]){ int v = gv[j] ; if(v == pre[aa]) continue ; pre[v] = ancer ; } } for(bb=b;bb!=ancer;bb=pre[bb]){ p[bb] = ancer ; for(int j=gr[bb] ;j!=-1;j=gnext[j]){ int v = gv[j] ; if(v == pre[bb]) continue ; pre[v] = ancer ; } }}int find(int a){ if(a != p[a]){ p[a] = find( p[a] ) ; } return p[a] ;}int main(){ int a, b ; int cas = 0 ; while(scanf("%d%d",&N,&M) == 2){ if(0==N && M==0) break ; ++cas ; init() ; for(int i=1;i<=M;i++){ scanf("%d%d",&a,&b); add(a,b); add(b,a); } solve(); memset(pre, -1, sizeof(pre)); build(0,-1); scanf("%d",&Q); ans = cnt - 1; printf("Case %d:\n",cas); for(int i=1;i<=Q;i++){ scanf("%d%d",&a,&b); int fa = find( col[a] ) ; int fb = find( col[b] ) ; if( fa == fb ){ printf("%d\n",ans); } else{ deal( fa,fb ); printf("%d\n",ans); } } printf("\n"); } return 0;}
- POJ_3694 Network Tarjin + LCA + 并查集
- LCA Tarjin 并查集 离线
- POJ 3694 Network lca + 并查集
- Network-POJ3694并查集+LCA
- Network-POJ3694并查集+LCA
- poj 3694 Network (连通图缩点+LCA+并查集)
- POJ-3694-Network(Tarjan+LCA+并查集)
- poj3728并查集+LCA
- [POJ 3694]Network(Tarjan+并查集+LCA 动态加边求图中桥的个数)
- 7_6_B题 Network题解[POJ3694] (LCA + 求桥 + 并查集)
- 【并查集】Wireless Network
- 并查集----Wireless Network
- Wireless Network 并查集
- Wireless Network 并查集
- POJ_2236_Wireless Network【并查集】
- Wireless Network --并查集
- LCA算法--并查集应用
- poj 3728(LCA+并查集应用)
- 关于数据库排序算法总结
- c++全局变量
- (C语言)共用体union的用法举例
- InnoDB隔离级别与锁机制.txt
- Android中的Activity四种启动模式(launchMode)
- POJ_3694 Network Tarjin + LCA + 并查集
- Shell脚本调试技术
- 判断完全二叉树
- IT大牛说的话,不得不记
- vmware网络模式设置(说的最简单的一篇文章) .
- 关于php 定时执行的一些想法
- java语言程序设计(基础篇) 第2章 基本程序设计 课本源代码
- 循环不变式(Loop invariant)
- Putty通过SSH自动登陆