#include <bits/stdc++.h>
using namespace std;
template <typename X, typename Y>
ostream &operator<<(ostream &o, pair<X, Y> &a) {
  o << "(" << a.first << "," << a.second << ")";
  return o;
}
template <typename X>
string join(X &a, const string delimiter) {
  stringstream ss;
  int i = 0;
  for (auto &x : a) {
    if (i++ > 0) ss << delimiter;
    ss << x;
  }
  return ss.str();
}
struct edgew {
  int u;
  int v;
  long long w;
  edgew(int u, int v, long long w) {
    this->u = u;
    this->v = v;
    this->w = w;
  }
  void unpack(int &u, int &v, long long &w) {
    u = this->u;
    v = this->v;
    w = this->w;
  }
};
ostream &operator<<(ostream &o, edgew &a) {
  o << "(" << a.u << "->" << a.v << "," << a.w << ")";
  return o;
}
const int N = 100005;
const int LOGN = 17;
vector<edgew> G[N];
vector<edgew> GT[N];
struct trees_lca {
  int T = 1, logn, n;
  vector<int> tin, tout;
  vector<long long> weight;
  vector<edgew> *G;
  vector<vector<int> > gpa;
  trees_lca(int n, vector<edgew> *G) {
    this->n = n;
    int nx = 1, logn = 0;
    while (nx <= n) logn++, nx <<= 1;
    this->logn = logn;
    this->G = G;
    gpa.resize(logn);
    for (int k = 0; k < logn; k++) gpa[k].resize(n);
    tin.resize(n);
    tout.resize(n);
    weight.resize(n);
    for (int i = 0; i < n; i++)
      if (tin[i] == 0) dfs(i);
    for (int k = 1; k < logn; k++)
      for (int i = 0; i < n; i++) {
        gpa[k][i] = gpa[k - 1][gpa[k - 1][i]];
      }
  }
  void dfs(int u) {
    tin[u] = T++;
    for (auto &e : G[u])
      if (tin[e.v] == 0) {
        weight[e.v] = weight[u] + e.w;
        gpa[0][e.v] = u;
        dfs(e.v);
      }
    tout[u] = T;
  }
  bool is_ancestor(int an, int x) {
    return tin[an] <= tin[x] && tout[an] >= tout[x];
  }
  int mth_parent(int i, int m) {
    for (int k = logn - 1; k >= 0; k--)
      if (m & (1 << k)) i = gpa[k][i];
    return i;
  }
  int lca(int a, int b) {
    if (is_ancestor(a, b)) return a;
    if (is_ancestor(b, a)) return b;
    for (int k = logn - 1; k >= 0; k--)
      if (!is_ancestor(gpa[k][a], b)) a = gpa[k][a];
    a = gpa[0][a];
    return is_ancestor(a, b) ? a : -1;
  }
  long long dist(int a, int b) {
    int x = lca(a, b);
    return x != -1 ? weight[a] + weight[b] - 2 * weight[x] : (1LL << 60);
  }
};
struct disjoint_set {
  vector<int> pa;
  disjoint_set(int n) {
    this->pa.resize(n);
    for (int i = 0; i < n; i++) this->pa[i] = i;
  }
  int find(int i) { return i == pa[i] ? i : pa[i] = find(pa[i]); }
  bool merge(int i, int j) {
    i = find(i);
    j = find(j);
    pa[i] = j;
    return i != j;
  }
};
vector<long long> dijkstra(int n, vector<edgew> *G, int src) {
  vector<long long> d(n);
  d.assign(n, (1LL << 60));
  set<pair<long long, int> > s;
  s.insert(make_pair(d[src] = 0, src));
  while (!s.empty()) {
    auto top = s.begin();
    auto du = top->first;
    auto u = top->second;
    s.erase(top);
    if (d[u] != du) continue;
    for (auto &e : G[u])
      if (du + e.w < d[e.v]) {
        s.insert(make_pair(d[e.v] = du + e.w, e.v));
      }
  }
  return d;
}
int main() {
  int n, m;
  while (scanf("%d%d", &n, &m) == 2) {
    disjoint_set ds(n);
    vector<int> specials;
    for (int i = 0; i < n; i++) G[i].clear();
    for (int i = 0; i < n; i++) GT[i].clear();
    for (int i = 0; i < m; i++) {
      int u, v, w;
      scanf("%d%d%d", &u, &v, &w), --u, --v;
      G[u].push_back(edgew(u, v, w));
      G[v].push_back(edgew(v, u, w));
      if (ds.merge(u, v)) {
        GT[u].push_back(edgew(u, v, w));
        GT[v].push_back(edgew(v, u, w));
      } else {
        specials.push_back(min(u, v));
      }
    }
    trees_lca T(n, GT);
    vector<vector<long long> > d;
    for (auto &src : specials) {
      d.push_back(dijkstra(n, G, src));
    }
    int nq;
    scanf("%d", &nq);
    for (int qtc = 0; qtc < nq; qtc++) {
      int u, v;
      scanf("%d%d", &u, &v);
      --u, --v;
      long long ans = T.dist(u, v);
      for (int j = 0; j < ((int)d.size()); j++)
        ans = min(ans, d[j][u] + d[j][v]);
      cout << ans << endl;
    }
  }
  return 0;
}
