题意:给n个点和m条边,再给出q条边,问每次加一条边以后剩下多少桥。
分析:这题是结合了LCA和dfn的妙用。_dfn数组和dfn的意义不一样,并非访问的时间戳,_dfn表示的是被访问的顺序,而且是多线程访问下的顺序,举个例子,同一个点分岔开来的点,距离这个点相同距离的点,他们的_dfn的值是相同的,而dfn不是,类似于单线程dfs访问的各点的dfn值是不同的。
具体见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <map> 5 #include <vector> 6 #include <queue> 7 using namespace std; 8 const int N = 100000 + 5; 9 10 int n,m,tot,head[N],cnt,dfs_clock,dfn[N],_dfn[N],root[N],low[N]; 11 bool bridge[N]; 12 struct edge 13 { 14 int nxt,v; 15 }edges[N<<2]; 16 17 void init() 18 { 19 tot = 0,dfs_clock = 0,cnt = 0; 20 memset(head,-1,sizeof(head)); 21 memset(dfn,0,sizeof(dfn)); 22 memset(_dfn,0,sizeof(_dfn)); 23 memset(bridge,false,sizeof(bridge)); 24 for(int i=1;i<=n;i++) root[i] = i; 25 } 26 27 void addEdge(int u,int v) 28 { 29 edges[tot] = (edge){head[u],v}; 30 head[u] = tot ++; 31 edges[tot] = (edge){head[v],u}; 32 head[v] = tot ++; 33 } 34 35 void tarjan(int u) 36 { 37 dfn[u] = low[u] = ++dfs_clock; 38 _dfn[u] = _dfn[root[u]] + 1; 39 for(int i=head[u];i!=-1;i=edges[i].nxt) 40 { 41 edge &e = edges[i]; 42 int v = e.v; 43 if(!dfn[v]) 44 { 45 root[v] = u; 46 tarjan(v); 47 low[u] = min(low[u],low[v]); 48 if(low[v] > dfn[u]) 49 { 50 cnt ++; 51 bridge[v] = true; 52 } 53 } 54 else if(dfn[v] < dfn[u] && v!=root[u]) low[u] = min(low[u],dfn[v]); 55 } 56 } 57 58 void LCA(int u,int v) 59 { 60 while(_dfn[u] > _dfn[v]) 61 { 62 if(bridge[u]) 63 { 64 cnt --; 65 bridge[u] = false; 66 } 67 u = root[u]; 68 } 69 while(_dfn[u] < _dfn[v]) 70 { 71 if(bridge[v]) 72 { 73 cnt --; 74 bridge[v] = false; 75 } 76 v = root[v]; 77 } 78 while(u != v) 79 { 80 if(bridge[u]) 81 { 82 cnt --; 83 bridge[u] = false; 84 } 85 if(bridge[v]) 86 { 87 cnt --; 88 bridge[v] = false; 89 } 90 u = root[u]; 91 v = root[v]; 92 } 93 } 94 95 void solve() 96 { 97 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 98 99 int q;scanf("%d",&q); 100 while(q--) 101 { 102 int u,v;scanf("%d%d",&u,&v); 103 LCA(u,v); 104 printf("%d ",cnt); 105 } 106 puts(""); 107 } 108 109 int main() 110 { 111 int kase = 1; 112 while(scanf("%d%d",&n,&m)==2) 113 { 114 if(n==0 && m==0) break; 115 init(); 116 printf("Case %d: ",kase++); 117 while(m--) 118 { 119 int u,v;scanf("%d%d",&u,&v); 120 addEdge(u,v); 121 } 122 solve(); 123 } 124 }