#include"string.h" #include"stdio.h" #include"iostream" #include"queue" #include"stack" #define M 10009 #define N 100009 #include"stdlib.h" #include"math.h" #define inf 99999999 using namespace std; struct node//构建原图 { int u,v,next,vis; }edge[N*2]; stack<int>q; int t,head[M],dfn[M],low[M],cut[M],use[N*2],index,num,belong[N*2]; struct Tree//缩点后的图 { int v; Tree(){} Tree(int vv):v(vv){} }; vector<Tree>Edge[M+N]; void init() { t=0; memset(head,-1,sizeof(head)); memset(edge,0,sizeof(edge)); } void add(int u,int v)//原图建边 { edge[t].u=u; edge[t].v=v; edge[t].next=head[u]; head[u]=t++; } void tarjan(int u,int fa) { dfn[u]=low[u]=++index; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].vis)continue; edge[i].vis=edge[i^1].vis=1; q.push(i); if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u])//求割点 { num++; cut[u]++; int j;//求边联通块 do { j=q.top(); q.pop(); belong[j]=belong[j^1]=num;//形成边连通块 }while(j!=i); } } else low[u]=min(low[u],dfn[v]); } if(fa<0) cut[u]--; } void solve(int n) { index=num=0; memset(dfn,0,sizeof(dfn)); memset(cut,0,sizeof(cut)); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1); } struct LCA { int u,v,w,next; }lca[N*3]; int t1,head1[N*2],f[N*2],dis[N*2]; void Init() { t1=0; memset(head1,-1,sizeof(head1)); } void Addlca(int u,int v) { lca[t1].u=u; lca[t1].v=v; lca[t1].next=head1[u]; head1[u]=t1++; } int finde(int x) { if(x!=f[x]) f[x]=finde(f[x]); return f[x]; } void make(int a,int b) { f[finde(a)]=finde(b); } void dfs(int u)//离线LCA算法 { use[u]=1; for(int i=0;i<(int)Edge[u].size();i++) { int v=Edge[u][i].v; if(!use[v]) { dis[v]=dis[u]+1; dfs(v); f[v]=u; make(u,v); } } for(int i=head1[u];i!=-1;i=lca[i].next) { int v=lca[i].v; if(use[v]) lca[i].w=lca[i^1].w=f[finde(v)]; } } void slove() { dis[1]=0; for(int i=0;i<=num;i++) f[i]=i; memset(use,0,sizeof(use)); for(int i=1;i<=num;i++) if(!use[i]) dfs(i); for(int i=0;i<t1;i+=2) { int u=lca[i].u; int v=lca[i].v; int mid=lca[i].w; printf("%d\n",(dis[u]+dis[v]-2*dis[mid])/2); } } int main() { int n,m,i,u,v; while(scanf("%d%d",&n,&m),m||n) { init(); for(i=0;i<m;i++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } solve(n);//求割点和边联通块 memset(use,0,sizeof(use)); for(u=1;u<=n;u++) { if(cut[u]) { ++num;//在边的联通块的序号之上继续给割点编号 for(i=head[u];i!=-1;i=edge[i].next) { if(!use[belong[i]])//某个割点和相邻某条边建边后即与边联通块连接,应该去重 { Edge[num].push_back(belong[i]); Edge[belong[i]].push_back(num); use[belong[i]]=1; } } for(i=head[u];i!=-1;i=edge[i].next) use[belong[i]]=0; } } int Q; scanf("%d",&Q); Init(); while(Q--) { scanf("%d%d",&u,&v);//输入的是原始边的排列序号 Addlca(belong[u*2-1],belong[v*2-1]);//把边映射到边联通块中 Addlca(belong[v*2-1],belong[u*2-1]); } slove(); for(i=0;i<=num;i++) Edge[i].clear(); } }