题目大意:给出一个无向图以及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_JUDGE 101 freopen("in.txt","r",stdin); 102 #endif 103 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: ",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 ",cnt_bridge); 131 if(Q==0) 132 printf(" "); 133 } 134 } 135 136 return 0; 137 }