1 /** 2 problem: http://poj.org/problem?id=3694 3 4 问每加一条边后剩下多少桥 5 因为是无向图,所以使用tarjan缩点后会成一棵树并维护pre数组 6 在树上连一条边(a,b)减少的桥数就是 7 a点到a点和b点的最近公共祖先(lca)的所有边+b点到a点和b点的最近公共祖先的所有边 8 在算桥的同时将这些点缩成一个点 9 即每个点color = 最近公共祖先color 10 同时维护pre数组 每个点的pre = 最近公共祖先的pre 即可 11 **/ 12 #include<stdio.h> 13 #include<stack> 14 #include<queue> 15 #include<algorithm> 16 using namespace std; 17 18 const int MAXN = 100005; 19 const int MAXM = 555555; 20 21 class Graphics{ 22 private: 23 struct Edge{ 24 int to, next; 25 bool bridge; 26 }edge[MAXM]; 27 struct Point{ 28 int dfn, low, color; 29 }point[MAXN]; 30 int first[MAXN], pre[MAXN], sign, sumOfPoint, dfnNum, colorNum, bridge; 31 bool vis[MAXN]; 32 stack<int> stk; 33 queue<int> bfs; 34 void tarjan(int u, int preEdge = -1){ 35 point[u].low = dfnNum; 36 point[u].dfn = dfnNum ++; 37 vis[u] = true; 38 stk.push(u); 39 for(int i = first[u]; i != -1; i = edge[i].next){ 40 int to = edge[i].to; 41 if((i^1) == preEdge) continue; 42 if(!point[to].dfn){ 43 pre[to] = u; ///如果下一个点没被访问过则更新一下下个点的pre 44 tarjan(to, i); 45 point[u].low = min(point[u].low, point[to].low); 46 if(point[to].low > point[u].dfn){ 47 edge[i].bridge = true; 48 edge[i^1].bridge = true; 49 bridge ++; 50 } 51 }else if(vis[to]){ 52 point[u].low = min(point[to].dfn, point[u].low); 53 } 54 } 55 if(point[u].dfn == point[u].low){ 56 vis[u] = false; 57 point[u].color = ++ colorNum; 58 while(stk.top() != u){ 59 pre[stk.top()] = pre[u]; ///缩点时,该环中的所有点pre等于时间戳最小点的pre 60 point[stk.top()].color = colorNum; 61 vis[stk.top()] = false; 62 stk.pop(); 63 } 64 stk.pop(); 65 } 66 } 67 public: 68 void clear(int n){ 69 sumOfPoint = n; 70 for(int i = 1; i <= n; i ++){ 71 first[i] = -1; 72 pre[i] = -1; 73 vis[i] = 0; 74 point[i].dfn = 0; 75 } 76 sign = colorNum = bridge = 0; 77 dfnNum = 1; 78 while(!stk.empty()) stk.pop(); 79 } 80 void addEdgeOneWay(int u, int v){ 81 edge[sign].to = v; 82 edge[sign].next = first[u]; 83 edge[sign].bridge = false; 84 first[u] = sign ++; 85 } 86 void addEdgeTwoWay(int u, int v){ 87 addEdgeOneWay(u, v); 88 addEdgeOneWay(v, u); 89 } 90 void tarjanAllPoint(){ 91 for(int i = 1; i <= sumOfPoint; i ++){ 92 if(!point[i].dfn) 93 tarjan(i); 94 } 95 } 96 int getAns(int a, int b){ 97 for(int i = 1; i <= colorNum; i ++){ 98 vis[i] = false; 99 } 100 vis[point[a].color] = true; 101 vis[point[b].color] = true; 102 int lca, lcacolor, ta = a, tb = b; 103 while(true){ 104 if(ta != -1) ta = pre[ta]; 105 if(tb != -1) tb = pre[tb]; 106 if(vis[point[ta].color]){ 107 lcacolor = point[ta].color; 108 lca = ta; 109 break; 110 } 111 if(vis[point[tb].color]){ 112 lcacolor = point[tb].color; 113 lca = tb; 114 break; 115 116 } 117 vis[point[ta].color] = true; 118 vis[point[tb].color] = true; 119 } 120 while(point[a].color != lcacolor){ 121 for(int i = first[a]; i != -1; i = edge[i].next){ 122 int to = edge[i].to; 123 if(to == pre[a] && edge[i].bridge){ 124 bridge --; 125 edge[i].bridge = false; 126 edge[i^1].bridge = false; 127 break; 128 } 129 } 130 point[a].color = lcacolor; 131 int tmp = pre[a]; 132 pre[a] = pre[lca]; 133 a = tmp; 134 } 135 while(point[b].color != lcacolor){ 136 for(int i = first[b]; i != -1; i = edge[i].next){ 137 int to = edge[i].to; 138 if(to == pre[b] && edge[i].bridge){ 139 bridge --; 140 edge[i].bridge = false; 141 edge[i^1].bridge = false; 142 break; 143 } 144 } 145 point[b].color = lcacolor; 146 int tmp = pre[b]; 147 pre[b] = pre[lca]; 148 b = tmp; 149 } 150 addEdgeTwoWay(a, b); 151 return bridge; 152 } 153 }graph; 154 155 int main(){ 156 int n, m, cas = 1; 157 while(scanf("%d%d", &n, &m) != EOF && m + n){ 158 graph.clear(n); 159 while(m --){ 160 int a, b; 161 scanf("%d%d", &a, &b); 162 graph.addEdgeTwoWay(a, b); 163 } 164 graph.tarjanAllPoint(); 165 int q; 166 scanf("%d", &q); 167 printf("Case %d: ", cas ++); 168 while(q --){ 169 int a, b; 170 scanf("%d%d", &a, &b); 171 printf("%d ", graph.getAns(a, b)); 172 } 173 putchar(' '); 174 } 175 return 0; 176 }