poj3694(动态询问割桥的数目)
给我们一个图,然后有q次加边的操作,问每次加完边之后有多少个桥存在
首先用dfs求出所有的桥,然后dfs的过程中生成了一棵dfs树,该树有的边是桥,有的不是,用bridge[v] = true , 表示v与fa[v]的连边是桥
当加入一个边u,v后, u,v,lca(u,v)上的边从割边变成了非割边。
至于lca,我们可以用dfs过程中的dfn标号来向上回溯。
因为dfn[u] > dfn[lca(u,v)], dfn[v] > dfn[lca(u,v])
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #include <algorithm> 6 #include <vector> 7 #include <stack> 8 #include <map> 9 #include <set> 10 #include <string> 11 #include <functional> 12 using namespace std; 13 14 const int N = 100000+10; 15 int head[N],next[N*4],to[N*4],e; 16 int dfn[N],low[N],dfs_clock,cut,bridge[N],pre[N]; 17 18 void init(int n) 19 { 20 e = dfs_clock = cut = 0; 21 memset(head,-1,sizeof(head)); 22 for(int i=1;i<=n;++i) 23 { 24 fa[i] = i; 25 dfn[i] = low[i] = bridge[i] = 0; 26 } 27 } 28 void addEdge(int u, int v) 29 { 30 to[e] = v; 31 next[e] = head[u]; 32 head[u] = e++; 33 } 34 35 void tarjan(int u, int f) 36 { 37 dfn[u] = low[u] = ++dfs_clock; 38 bool flag = false; 39 for(int i=head[u]; i!=-1; i=next[i]) 40 { 41 int v = to[i]; 42 if(v==f && !flag) 43 { 44 flag=true; 45 continue; 46 } 47 if(dfn[v]==0) 48 { 49 pre[v] = u; 50 tarjan(v,u); 51 } 52 low[u] = min(low[v],low[u]); 53 if(low[v] > dfn[u]) 54 { 55 bridge[v] = true; 56 cut++; 57 } 58 } 59 } 60 61 void lca(int u, int v) 62 { 63 if(dfn[u] < dfn[v]) 64 swap(u,v); 65 while(dfn[u] > dfn[v])//回溯完后u就是lca 66 { 67 68 if(bridge[u]) 69 { 70 cut--; 71 bridge[u] = false; 72 } 73 u = pre[u]; 74 } 75 while(dfn[u] < dfn[v]) 76 { 77 78 if(bridge[v]) 79 { 80 cut--; 81 bridge[v] = false; 82 } 83 v = pre[v]; 84 } 85 } 86 int main() 87 { 88 int n,m; 89 int u,v; 90 int tcase = 1; 91 while(scanf("%d%d",&n,&m),n+m) 92 { 93 init(n); 94 for(int i=1;i<=m;++i) 95 { 96 scanf("%d%d",&u,&v); 97 addEdge(u,v);addEdge(v,u); 98 } 99 printf("Case %d:\n",tcase++); 100 tarjan(1,-1); 101 int q; 102 scanf("%d",&q); 103 while(q--) 104 { 105 scanf("%d%d",&u,&v); 106 lca(u,v); 107 printf("%d\n",cut); 108 } 109 puts(""); 110 } 111 return 0; 112 }