#include using namespace std; using ll = long long; using pll = pair; #define vc vector using vl = vc; #define ov(a, b, c, name, ...) name #define rep2(i, l, r) for(ll i = (l); i < ll(r); i++) #define rep1(i, n) rep2(i, 0, n) #define rep(...) ov(__VA_ARGS__, rep2, rep1)(__VA_ARGS__) #define fec(...) for(const auto& __VA_ARGS__) #define per(i, a, b) for(ll i = ll(a) - 1; i >= ll(b); i--) #define ALL(x) begin(x), end(x) #define SZ(x) (ll) size(x) #define LB(v, x) (lower_bound(ALL(v), x) - begin(v)) #define eb emplace_back bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; } bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; } const ll INF = ll(4e18) + 100; void printvec(const auto& v) { for(auto it = begin(v); it != end(v); it++) cout << *it << " "; cout << endl; } #ifdef LOCAL #define local(...) __VA_ARGS__ #else #define local(...) #endif template struct LL { int n; const G g; vc ord, low, arti; vector bridge; LL(G g) : n(g.size()), g(g), ord(n, -1), low(n, -1) { int k = 0; rep(i, n) { if(ord[i] == -1) k = dfs(i, k, -1); } } int dfs(int x, int k, int p) { low[x] = ord[x] = k++; int cnt = 0; bool is_arti = false, second = false; fec(e : g[x]) { if(ord[e] == -1) { cnt++; k = dfs(e, k, x); chmin(low[x], low[e]); is_arti |= (p != -1) && (low[e] >= ord[x]); if(ord[x] < low[e]) bridge.eb(minmax(x, e)); } else if(e != p or second) { chmin(low[x], ord[e]); } else { second = true; } } is_arti |= p == -1 && cnt > 1; if(is_arti) arti.eb(x); return k; } }; // depends on lowlink // 二重連結成分: 二重連結 (どの頂点を削除しても連結のまま) かつ極大な部分グラフ // bc には辺集合が入る // 辺はちょうど一つの bcc に属するが、頂点は複数の bcc に属することもある // bc.size() は **孤立点以外の** bcc の個数 template struct BCC : LL { vc used; vc> bc; vc tmp; using L = LL; using L::g; using L::low; using L::ord; BCC(G g) : L(g) { used.assign(g.size(), 0); rep(i, used.size()) if(!used[i]) dfs(i, -1); } void dfs(int x, int p) { used[x] = true; fec(e : g[x]) { if(e == p) continue; if(!used[e] || ord[e] < ord[x]) tmp.eb(minmax(x, e)); if(used[e]) continue; dfs(e, x); if(low[e] >= ord[x]) { bc.eb(); while(true) { auto p = tmp.back(); bc.back().eb(p); tmp.pop_back(); if(p == (pll)minmax(x, e)) break; } } } } }; // depends on lowlink, bcc // 関節点 (an 個) と二重連結成分 (bn 個) からなる森 (tree に格納) // 頂点番号は [0, an) と [an, an+bn) // vtoi[v]: もとのグラフの頂点 v → BCT の頂点 i // (関節点は関節点、それ以外は属する唯一の二重連結成分) // 孤立点は -1 になるので注意 template struct BCT : BCC { using B = BCC; using B::bc; using B::L::arti; vc> tree; vc vtoi; int an, bn; BCT(const G &g) : B(g) { an = arti.size(), bn = bc.size(); tree.resize(an + bn); vtoi.resize(g.size(), -1); rep(i, an) vtoi[arti[i]] = i; rep(j, bn) fec([u, v] : bc[j]) fec(w : {u, v}) { int &i = vtoi[w]; if(0 <= i && i < an) { if (tree[i].empty() || tree[i].back() != an + j) { tree[i].eb(an + j), tree[an + j].eb(i); } } else i = an + j; } } }; template struct HLD { int n; G& g; vc sub, in, out, head, rev, par, d; HLD(G& g, int root = 0) : n(g.size()), g(g), sub(n), in(n), out(n), head(n), rev(n), par(n), d(n) { int t = 0; head[root] = 0; dfs1(root, -1); dfs2(root, -1, t); } void dfs1(int x, int p) { par[x] = p; sub[x] = 1; if(g[x].size() and g[x][0] == p) swap(g[x][0], g[x].back()); for(auto &e : g[x]) { if(e == p) continue; d[e] = d[x] + 1; dfs1(e, x); sub[x] += sub[e]; if(sub[g[x][0]] < sub[e]) swap(g[x][0], e); } } void dfs2(int x, int p, int& t) { in[x] = t++; rev[in[x]] = x; fec(e : g[x]) { if(e == p) continue; head[e] = (g[x][0] == e ? head[x] : e); dfs2(e, x, t); } out[x] = t; } int la(int v, int k) { while(1) { int u = head[v]; if(in[v] - k >= in[u]) return rev[in[v] - k]; k -= in[v] - in[u] + 1; v = par[u]; } } int lca(int u, int v) { for(;; v = par[head[v]]) { if(in[u] > in[v]) swap(u, v); if(head[u] == head[v]) return u; } } template T query(int u, int v, const T& e, const Q& q, const F& f, bool edge = false) { T l = e, r = e; for(;; v = par[head[v]]) { if(in[u] > in[v]) swap(u, v), swap(l, r); if(head[u] == head[v]) break; l = f(q(in[head[v]], in[v] + 1), l); } return f(f(q(in[u] + edge, in[v] + 1), l), r); } int dist(int u, int v) { return d[u] + d[v] - 2 * d[lca(u, v)]; } int jump(int s, int t, int i) { if(!i) return s; int l = lca(s, t); int dst = d[s] + d[t] - d[l] * 2; if(dst < i) return -1; if(d[s] - d[l] >= i) return la(s, i); i -= d[s] - d[l]; return la(t, d[t] - d[l] - i); } }; int main() { ll N, M; cin >> N >> M; vc G(N); rep(i, M) { ll u, v; cin >> u >> v; u--, v--; G.at(u).eb(v); G.at(v).eb(u); } BCT bct(G); auto& H = bct.tree; ll K = bct.an + bct.bn; local(rep(i, K) printvec(H.at(i))); local(printvec(bct.vtoi)); HLD hld(H); vl dp(K); dp.at(0) = 0 < bct.an; queue que; que.push(0); while(!que.empty()) { ll v = que.front(); que.pop(); fec(c : H.at(v)) { if(hld.par.at(v) == c) continue; dp.at(c) = dp.at(v) + (c < bct.an); que.push(c); } } local(printvec(dp)); ll Q; cin >> Q; rep(_, Q) { ll u, v; cin >> u >> v; u--, v--; if(u == v) { cout << 0 << "\n"; continue; } ll i = bct.vtoi.at(u), j = bct.vtoi.at(v); ll k = hld.lca(i, j); local(cout << u << " " << v << " " << i << " " << j << " " << k << endl); ll ans = dp.at(i) + dp.at(j) - dp.at(k) - (k == 0 ? 0 : dp.at(hld.par.at(k))) - (i < bct.an) - (j < bct.an); cout << ans << "\n"; } }