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:\n", cas ++);
168 while(q --){
169 int a, b;
170 scanf("%d%d", &a, &b);
171 printf("%d\n", graph.getAns(a, b));
172 }
173 putchar('\n');
174 }
175 return 0;
176 }