首页 > 代码库 > hdu2460-Network:边的双连通分量

hdu2460-Network:边的双连通分量

题目大意:给出一个无向图以及Q次询问,每次询问增加一条无向边,要求输出增加这条边后剩余的桥的数目。

算法:类似于求割点的方法,先做一次dfs求出所有的桥,并且维护这棵dfs树,当一次询问加入一条边(a,b)之后,会在dfs上形成一个环,在这个环上的桥都变为非桥,这个环肯定经过a和b的LCA,此时我们只需在求LCA的过程中把经过的为桥的树边标记为非桥,同时cnt_bridge--再输出即可。

需要注意的是树边的编号是用树边指向的那个节点的编号来表示的,例如树边<u,v>用编号v表示。

还有就是加入一个#pragma预处理指令可以防止爆栈。

 

  1 #include <iostream>  2 #include <stdio.h>  3 #include <cstring>  4 #include <vector>  5 using namespace std;  6 #pragma comment(linker,"/STACk:10240000,10240000")  7   8 const int maxn = 100000 + 10;  9 int low[maxn],pre[maxn], iscut[maxn], dfs_clock=0; 10 bool isbridge[maxn]; 11 vector<int> G[maxn]; 12 int cnt_bridge; 13 int father[maxn]; 14  15 int dfs(int u, int fa) 16 { 17     father[u]=fa; 18     int lowu = pre[u] = ++dfs_clock; 19     int child = 0; 20     for(int i = 0; i < G[u].size(); i++) 21     { 22         int v = G[u][i]; 23         if(!pre[v])   // 没有访问过v 24         { 25             child++; 26             int lowv = dfs(v, u); 27             lowu = min(lowu, lowv); // 用后代的low函数更新自己 28             if(lowv > pre[u]) // 判断边(u,v)是否为桥 29             { 30                 isbridge[v]=true; 31                 cnt_bridge++; 32             } 33         } 34         else if(pre[v] < pre[u] && v != fa) 35         { 36             lowu = min(lowu, pre[v]); // 用反向边更新自己 37         } 38     } 39     if(fa < 0 && child == 1) 40         iscut[u] = 0; 41     return low[u]=lowu; 42 } 43  44 void init(int n) 45 { 46     memset(isbridge,false,sizeof isbridge); 47     memset(pre,0,sizeof pre); 48     cnt_bridge=dfs_clock=0; 49     for(int i=0; i<n; i++) 50     { 51         G[i].clear(); 52     } 53 } 54  55 void LCA(int a,int b) 56 { 57     while(pre[a]>pre[b]) 58     { 59         if(isbridge[a]) 60         { 61             isbridge[a]=false; 62             cnt_bridge--; 63         } 64         a=father[a]; 65     } 66     while(pre[b]>pre[a]) 67     { 68         if(isbridge[b]) 69         { 70             isbridge[b]=false; 71             cnt_bridge--; 72         } 73         b=father[b]; 74     } 75     if(a!=b) 76     { 77         while(pre[a]>pre[b]) 78         { 79             if(isbridge[a]) 80             { 81                 isbridge[a]=false; 82                 cnt_bridge--; 83             } 84             a=father[a]; 85         } 86         while(pre[b]>pre[a]) 87         { 88             if(isbridge[b]) 89             { 90                 isbridge[b]=false; 91                 cnt_bridge--; 92             } 93             b=father[b]; 94         } 95     } 96 } 97  98 int main() 99 {100 #ifndef ONLINE_JUDGE101     freopen("in.txt","r",stdin);102 #endif103 104     int n,m,Case=1;105     while(scanf("%d %d",&n,&m),!(n==0 && m==0))106     {107         init(n);108         for(int i=0; i<m; i++)109         {110             int a,b;111             scanf("%d %d",&a,&b);112             a--;113             b--;114             G[a].push_back(b);115             G[b].push_back(a);116         }117 118         // 第一次dfs找出所有的桥119         dfs(0,-1);120         int Q;121         cin>>Q;122         printf("Case %d:\n",Case++);123         while(Q--)124         {125             int a,b;126             scanf("%d %d",&a,&b);127             a--;128             b--;129             LCA(a,b);130             printf("%d\n",cnt_bridge);131             if(Q==0)132                 printf("\n");133         }134     }135 136     return 0;137 }

 

hdu2460-Network:边的双连通分量