- 无向图的必经边问题
- 求无向图的边双连通分量,由于涉及到对边的标记,因此需要采用链式前向星存图
#include <bits/stdc++.h>
using namespace std;
int n,m,cnt;
vector<int>a[100005],c;
int h[100005],nx[400005],to[400005];
int dfn[100005],low[100005],tot,id[100005];
int d[100005],f[100005][20];
bool cut[400005];
void tarjan(int n1,int fa)
{dfn[n1]=low[n1]=++tot;for(int i=h[n1];i;i=nx[i]){int y=to[i];if(!dfn[y]){tarjan(y,n1);low[n1]=min(low[n1],low[y]);if(dfn[n1]<low[y]){cut[i]=cut[i^1]=true;c.push_back(i);}}else if(y!=fa){low[n1]=min(low[n1],dfn[y]);}}
}
void dfs1(int n1)
{for(int i=h[n1];i;i=nx[i]){if(cut[i]==true){continue;}if(!id[to[i]]){id[to[i]]=id[n1];dfs1(to[i]);}}
}
void dfs2(int n1)
{for(int i=0;i<a[n1].size();i++){if(a[n1][i]!=f[n1][0]){f[a[n1][i]][0]=n1;d[a[n1][i]]=d[n1]+1;dfs2(a[n1][i]);}}
}
void add(int u,int v)
{tot++;to[tot]=v;nx[tot]=h[u];h[u]=tot;
}
int lca(int u,int v)
{if(d[u]<d[v]){swap(u,v);}for(int i=16;i>=0;i--){if(d[f[u][i]]>=d[v]){u=f[u][i];}}if(u==v){return u;}for(int i=16;i>=0;i--){if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}}return f[u][0];
}
void pre()
{for(int j=1;j<=16;j++){for(int i=1;i<=cnt;i++){f[i][j]=f[f[i][j-1]][j-1];}}
}
int dist(int u,int v)
{return d[u]+d[v]-2*d[lca(u,v)];
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cin>>n>>m;tot=1;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;add(u,v);add(v,u);}tot=0;tarjan(1,0);for(int i=1;i<=n;i++){if(!id[i]){id[i]=++cnt;dfs1(i);}}for(int i=0;i<c.size();i++){a[id[to[c[i]]]].push_back(id[to[c[i]^1]]);a[id[to[c[i]^1]]].push_back(id[to[c[i]]]);}d[1]=1;dfs2(1);pre();int q;cin>>q;for(int i=1;i<=q;i++){int u,v;cin>>u>>v;cout<<dist(id[u],id[v])<<"\n";}return 0;
}