Everybody knows that totalfrank has absolutely no sense of direction. Getting lost in the university or nearly supermarket is very common for him. We always worry about whether he can find his way back into our sweet base whenever he goes out alone for his class. In general, if totalfrank get lost again, we need to check his starting point and destination just in order to find out where he could be (you know this task is very common for us).
Unfortunately, poor totalfrank sometimes forgot taking his mobile phone, when this situation happens, we can’t get in touch with him. But it is so lucky that totalfrank can remember places where he had gone before in his trip from his starting point and destination at this trip so that he won’t go to such place again (he can’t remember places which he had gone during his previous trip). As we are all familiar with map, we can find out which place he couldn’t be.
However, totalfrank can always get lost, doing this same boring work makes us sleepy. So we ask totalfrank for all possible starting point and destination for him, and try to find out how many places he wouldn’t be when he chooses any pair of starting point and destination. Here comes the problem, since our university’s map is so complex (there can be many buildings which can be considered as points in our university, some pair of these point has a way while others hasn’t), we need a program to help us work out this problem.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #pragma comment(linker, "/STACK:102400000,102400000")
2 #include <string.h>
3 #include <stdio.h>
4 #include <math.h>
5 #include <algorithm>
6 const int MAXN=1e5+5;
7
8 struct edge{
9 int u,v,n;
10 }e1[MAXN*4],e2[MAXN*4];
11
12 int f1[MAXN],f2[MAXN*2],es1,es2;
13 int n,m,q,tu,tv;
14
15 void addedge1(int u,int v){
16 e1[es1].u=u,e1[es1].v=v,e1[es1].n=f1[u],f1[u]=es1++;
17 }
18
19 void addedge2(int u,int v){
20 e2[es2].u=u,e2[es2].v=v,e2[es2].n=f2[u],f2[u]=es2++;
21 }
22
23 int p[MAXN*2];
24
25 int find(int x){return x==p[x]?x:p[x]=find(p[x]);}
26
27 void merge(int x,int y){p[find(x)]=find(y);}
28
29 int sum[MAXN*2],tsum[MAXN*2],dis[MAXN];
30 int lca_f[MAXN*4],lca_b[MAXN*4],lca_p[MAXN*2],rid;
31 int dminv[MAXN*4][20],dminid[MAXN*4][20];
32
33 void dp(int u,int f,int dd,int tot){
34 dis[u]=dd,tsum[u]=tot+sum[u];
35 lca_f[++rid]=u,lca_b[rid]=dd,lca_p[u]=rid;
36 for(int i=f2[u];i!=-1;i=e2[i].n){
37 int v=e2[i].v;
38 if(v==f)continue;
39 dp(v,u,dd+1,tot+sum[u]);
40 lca_f[++rid]=u,lca_b[rid]=dd;
41 }
42 }
43
44 void makermq(){
45 rid=0;
46 dp(0,-1,0,0);
47 for(int i=1;i<=rid;i++)dminv[i][0]=lca_b[i],dminid[i][0]=i;
48 int maxj=(int)(log(rid+1.0)/log(2.0));
49 for(int j=1;j<=maxj;j++){
50 int maxi=rid+1-(1<<j);
51 for(int i=1;i<=maxi;i++){
52 if(dminv[i][j-1]<dminv[i+(1<<(j-1))][j-1]){
53 dminv[i][j]=dminv[i][j-1];
54 dminid[i][j]=dminid[i][j-1];
55 }else{
56 dminv[i][j]=dminv[i+(1<<(j-1))][j-1];
57 dminid[i][j]=dminid[i+(1<<(j-1))][j-1];
58 }
59 }
60 }
61 }
62
63 int lca(int x,int y){
64 if(lca_p[x]>lca_p[y])std::swap(x,y);
65 x=lca_p[x],y=lca_p[y];
66 int k=(int)(log(y-x+1.0)/log(2.0));
67 int xx=dminv[x][k]<dminv[y+1-(1<<k)][k]?dminid[x][k]:dminid[y+1-(1<<k)][k];
68 return lca_f[xx];
69 }
70
71 int dfn[MAXN],low[MAXN],cid[MAXN],stk[MAXN],col[MAXN],top,ind,cls,tmp;
72 int cal[MAXN*2];
73
74 void dfs_cutpnt(int u,int f,int root){
75 dfn[u]=low[u]=++ind;
76 int cnt=0;
77 int flag=0;
78 for(int i=f1[u];i!=-1;i=e1[i].n){
79 int v=e1[i].v;
80 if(v==f&&!flag){flag=1;continue;}
81 if(!dfn[v]){
82 cnt++;
83 dfs_cutpnt(v,u,root);
84 if(low[v]<low[u])low[u]=low[v];
85 if(u==root&&cnt>1&&cid[u]==0)cid[u]=++cls,sum[cls]=1;
86 else if(u!=root&&low[v]>=dfn[u]&&cid[u]==0)cid[u]=++cls,sum[cls]=1;
87 }else if(dfn[v]<low[u])low[u]=dfn[v];
88 }
89 }
90
91 void dfs_tarjan(int u,int f){
92 low[u]=dfn[u]=++ind;
93 stk[++top]=u;
94 int flag=0;
95 for(int i=f1[u];i!=-1;i=e1[i].n){
96 int v=e1[i].v;
97 if(v==f&&!flag){flag=1;continue;}
98 if(!dfn[v]){
99 dfs_tarjan(v,u);
100 if(low[v]<low[u])low[u]=low[v];
101 if(low[v]>=dfn[u]){
102 sum[++cls]=1,col[u]=cls;
103 do{
104 tmp=stk[top--],col[tmp]=cls,++sum[cls];
105 if(cid[tmp]){addedge2(cid[tmp],cls);addedge2(cls,cid[tmp]);merge(cid[tmp],cls);}
106 }while(tmp!=v);
107 if(cid[u]){addedge2(cid[u],cls);addedge2(cls,cid[u]);merge(cid[u],cls);}
108 }
109 }else if(dfn[v]<low[u])low[u]=dfn[v];
110 }
111 }
112
113 int size;
114
115 void makegraph(){
116 //找割点
117 memset(dfn,0,sizeof dfn);
118 memset(low,0,sizeof low);
119 memset(cid,0,sizeof cid);
120 cls=ind=0;
121 //找双联通分量并建图
122 for(int i=0;i<n;i++)dfs_cutpnt(i,-1,i);
123 memset(dfn,0,sizeof dfn);
124 memset(low,0,sizeof low);
125 memset(col,0,sizeof col);
126 top=ind=0;
127 for(int i=0;i<n;i++)dfs_tarjan(i,-1);
128 //将森林补成树,便于dp以及查询
129 memset(cal,0,sizeof cal);
130 for(int i=1;i<=cls;i++){
131 if(cal[find(i)]==0){
132 cal[find(i)]=1;
133 addedge2(0,i);
134 }
135 }
136 }
137
138 int main(){
139 //freopen("test.in","r",stdin);
140 int cas=1;
141 while(scanf("%d%d",&n,&m)!=EOF){
142 memset(f1,-1,sizeof f1);
143 memset(f2,-1,sizeof f2);
144 for(int i=0;i<=2*n;i++)p[i]=i;
145 es1=es2=0;
146
147 for(int i=0;i<m;i++){
148 scanf("%d%d",&tu,&tv);
149 addedge1(tu,tv);
150 addedge1(tv,tu);
151 }
152
153 //转化成双联通与割点相邻的图
154 makegraph();
155 //lca转化成rmq
156 makermq();
157
158 printf("Case #%d:
",cas++);
159 scanf("%d",&q);
160 while(q--){
161 scanf("%d%d",&tu,&tv);
162 //起点和终点重合
163 if(tu==tv)printf("%d
",n-1);
164 else{
165 //如果是割点的话就一定要用割点对应的点,因为割点会被染成不同的颜色!
166 tu=cid[tu]?cid[tu]:col[tu];
167 tv=cid[tv]?cid[tv]:col[tv];
168 //孤立点或者不在同一个联通块中
169 if(tu==0||tv==0||find(tu)!=find(tv)){
170 printf("%d
",n);
171 }else{
172 int fa=lca(tu,tv);
173 int ans=tsum[tu]+tsum[tv]-2*tsum[fa]+sum[fa];
174 ans-=(dis[tu]+dis[tv]-2*dis[fa]);
175 printf("%d
",n-ans);
176 }
177 }
178 }
179 printf("
");
180 }
181 return 0;
182 }