#include <bits/stdc++.h>
using namespace std;
template <typename T>
class Segment {
 public:
  T sum;
  T range_min;
  T left_min;
  T right_min;
  T mn;
  Segment()
      : sum(0),
        range_min(std::numeric_limits<T>::max()),
        left_min(std::numeric_limits<T>::max()),
        right_min(std::numeric_limits<T>::max()),
        mn(std::numeric_limits<T>::max()) {}
  Segment(T x) : sum(x), range_min(x), left_min(x), right_min(x), mn(x) {}
  Segment<T> operator=(const T& x);
  Segment<T> operator+=(const Segment<T>& b);

 private:
  T add(T a, T b);
  void Swap(Segment<T>& tmp);
};
template <typename T>
Segment<T> Segment<T>::operator=(const T& x) {
  sum = x;
  range_min = x;
  left_min = x;
  right_min = x;
  mn = x;
  return *this;
}
template <typename T>
void Segment<T>::Swap(Segment<T>& a) {
  swap(sum, a.sum);
  swap(range_min, a.range_min);
  swap(left_min, a.left_min);
  swap(right_min, a.right_min);
  swap(mn, a.mn);
}
template <typename T>
T Segment<T>::add(T a, T b) {
  T ret;
  if (a == std::numeric_limits<T>::max() ||
      b == std::numeric_limits<T>::max()) {
    ret = std::numeric_limits<T>::max();
  } else {
    ret = a + b;
  }
  return ret;
}
template <typename T>
Segment<T> Segment<T>::operator+=(const Segment<T>& b) {
  Segment<T> tmp(*this);
  tmp.sum = this->sum + b.sum;
  tmp.range_min =
      min(min(this->range_min, b.range_min), this->right_min + b.left_min);
  tmp.left_min = min(this->left_min, add(this->sum, b.left_min));
  tmp.right_min = min(add(this->right_min, b.sum), b.right_min);
  tmp.mn = min(this->mn, b.mn);
  Swap(tmp);
  return *this;
}
template <typename T>
Segment<T> operator+(const Segment<T>& a, const Segment<T>& b) {
  Segment<T> ret(a);
  ret += b;
  return ret;
}
template <typename T>
class RMQ {
 private:
  int n;
  int nn;
  Segment<T> query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l) {
      return Segment<T>();
    }
    if (a <= l && r <= b) {
      return val[k];
    } else {
      Segment<T> vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
      Segment<T> vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
      return vl + vr;
    }
  }
  bool bound_check(int a, int b) {
    if (a >= b) {
      return false;
    }
    if (a < 0 || n < b) {
      return false;
    }
    return true;
  }
  std::vector<Segment<T> > val;

 public:
  RMQ(int _n) : n(_n) {
    nn = 1;
    while (n > nn) nn *= 2;
    val.resize(nn * 2 - 1);
    for (size_t i = 0; i < val.size(); ++i) {
      val[i] = (std::numeric_limits<T>::max());
    }
  }
  RMQ() {}
  RMQ(const std::vector<T>& v) {
    n = static_cast<T>(v.size());
    nn = 1;
    while (n > nn) nn *= 2;
    val.resize(nn * 2 - 1);
    for (size_t i = 0; i < val.size(); ++i) {
      val[i] = (std::numeric_limits<T>::max());
    }
    for (size_t i = 0; i < v.size(); ++i) {
      update(i, v[i]);
    }
  }
  inline size_t size() { return n; }
  T operator[](int idx) {
    if (idx < 0 || n < idx) {
      throw "out of range";
    }
    return val[idx + nn - 1].mn;
  }
  void update(int i, T x) {
    if (i < 0 || n < i) {
      throw "out of range";
    }
    i += nn - 1;
    val[i] = x;
    while (i > 0) {
      i = (i - 1) / 2;
      val[i] = val[i * 2 + 1] + val[i * 2 + 2];
    }
  }
  T mn(int a, int b) {
    if (!bound_check(a, b)) {
      throw "invalid range";
    }
    return query(a, b, 0, 0, nn).mn;
  }
  T range_min(int a, int b) {
    if (!bound_check(a, b)) {
      throw "invalid range";
    }
    return query(a, b, 0, 0, nn).range_min;
  }
  T sum(int a, int b) {
    if (!bound_check(a, b)) {
      return T();
    }
    return query(a, b, 0, 0, nn).sum;
  }
};
class LCA {
 public:
  LCA(int n);
  void init(const std::vector<std::vector<int> >& adj_list, int root);
  int query(int x, int y);
  void dump();

 private:
  void bfs();
  void dfs(int now);
  int n_;
  int root_;
  RMQ<int> rmq;
  std::vector<std::vector<int> > adj_;
  std::vector<int> id2bfsid_;
  std::vector<int> bfsid2id_;
  std::vector<int> euler_;
  std::vector<int> id2euler_;
};
LCA::LCA(int n) : rmq(2 * n - 1) {}
void LCA::init(const vector<vector<int> >& adj_list, int root) {
  n_ = adj_list.size();
  root_ = root;
  adj_ = adj_list;
  id2bfsid_.clear();
  id2bfsid_.resize(n_, -1);
  bfsid2id_.clear();
  bfs();
  euler_.clear();
  id2euler_.clear();
  id2euler_.resize(n_, -1);
  dfs(root);
}
void LCA::bfs() {
  queue<int> q;
  q.push(root_);
  while (!q.empty()) {
    int now = q.front();
    q.pop();
    if (id2bfsid_[now] != -1) {
      continue;
    }
    id2bfsid_[now] = static_cast<int>(bfsid2id_.size());
    bfsid2id_.push_back(now);
    for (size_t i = 0; i < adj_[now].size(); ++i) {
      q.push(adj_[now][i]);
    }
  }
}
void LCA::dfs(int now) {
  id2euler_[now] = static_cast<int>(euler_.size());
  rmq.update(euler_.size(), id2bfsid_[now]);
  euler_.push_back(now);
  for (size_t i = 0; i < adj_[now].size(); ++i) {
    int next = adj_[now][i];
    if (id2euler_[next] != -1) {
      continue;
    }
    dfs(next);
    rmq.update(euler_.size(), id2bfsid_[now]);
    euler_.push_back(now);
  }
}
int LCA::query(int x, int y) {
  int euler_x = id2euler_[x];
  int euler_y = id2euler_[y];
  if (euler_x > euler_y) {
    swap(euler_x, euler_y);
  }
  int ret_bfsid = rmq.mn(euler_x, euler_y + 1);
  return bfsid2id_[ret_bfsid];
}
int n, m;
vector<vector<pair<int, int> > > adj;
vector<vector<int> > tree;
int id[100010];
int minid[100010];
bool is_bridge[100010];
int cc_idx;
int cc[100010];
int depth[100010];
int dfs(int now, int prev, int visit_num) {
  id[now] = minid[now] = visit_num;
  ++visit_num;
  for (size_t i = 0; i < adj[now].size(); ++i) {
    int next = adj[now][i].first;
    if (next == prev) {
      continue;
    }
    if (id[next] == -1) {
      visit_num = dfs(next, now, visit_num);
      if (id[next] == minid[next]) {
        is_bridge[adj[now][i].second] = true;
      }
    }
    minid[now] = min(minid[now], minid[next]);
  }
  return visit_num;
}
void detect_bridge() {
  memset(id, ~0, sizeof(id));
  memset(minid, ~0, sizeof(minid));
  memset(is_bridge, false, sizeof(is_bridge));
  dfs(0, -1, 0);
}
void dfs2(int now, int cc_idx) {
  cc[now] = cc_idx;
  for (size_t i = 0; i < adj[now].size(); ++i) {
    int next = adj[now][i].first;
    if (cc[next] != -1) {
      continue;
    }
    if (is_bridge[adj[now][i].second]) {
      continue;
    }
    dfs2(next, cc_idx);
  }
}
void connected_component() {
  memset(cc, ~0, sizeof(cc));
  cc_idx = 0;
  for (int i = 0; i < n; ++i) {
    if (cc[i] == -1) {
      dfs2(i, cc_idx);
      ++cc_idx;
    }
  }
}
int used[100010];
void dfs3(int now, int d) {
  depth[cc[now]] = d;
  used[now] = 1;
  for (size_t i = 0; i < adj[now].size(); ++i) {
    int next = adj[now][i].first;
    if (used[next] == 1) {
      continue;
    }
    if (is_bridge[adj[now][i].second]) {
      dfs3(next, d + 1);
      tree[cc[now]].push_back(cc[next]);
      tree[cc[next]].push_back(cc[now]);
    } else {
      dfs3(next, d);
    }
  }
}
void create_tree() {
  tree.clear();
  tree.resize(cc_idx);
  memset(depth, ~0, sizeof(depth));
  memset(used, 0, sizeof(used));
  dfs3(0, 0);
}
int main() {
  while (cin >> n >> m) {
    adj.clear();
    adj.resize(n);
    for (int i = 0; i < (int)(m); i++) {
      int a, b;
      cin >> a >> b;
      --a;
      --b;
      adj[a].push_back(make_pair(b, i));
      adj[b].push_back(make_pair(a, i));
    }
    detect_bridge();
    connected_component();
    create_tree();
    LCA lca(cc_idx);
    lca.init(tree, 0);
    int k;
    cin >> k;
    for (int i = 0; i < (int)(k); i++) {
      int s, d;
      cin >> s >> d;
      --s;
      --d;
      int ancestor = lca.query(cc[s], cc[d]);
      cout << depth[cc[s]] + depth[cc[d]] - 2 * depth[ancestor] << endl;
    }
  }
  return 0;
}
