#pragma GCC optimize("O3") #include using namespace std; const int INF = 10000000; const long long MOD = 1000000007; struct unionfind{ vector p; unionfind(int N){ p = vector(N, -1); } int root(int x){ if (p[x] < 0){ return x; } else { p[x] = root(p[x]); return p[x]; } } bool same(int x, int y){ return root(x) == root(y); } void unite(int x, int y){ x = root(x); y = root(y); if (x != y){ if (p[x] < p[y]){ swap(x, y); } p[y] += p[x]; p[x] = y; } } }; struct dual_segment_tree{ int N; vector ST; dual_segment_tree(){ } dual_segment_tree(int N2){ N = 1; while (N < N2){ N *= 2; } ST = vector(N * 2 - 1, INF); } int operator [](int k){ k += N - 1; int ans = ST[k]; while (k > 0){ k = (k - 1) / 2; ans = min(ans, ST[k]); } return ans; } void range_chmin(int L, int R, int x, int i, int l, int r){ if (r <= L || R <= l){ return; } else if (L <= l && r <= R){ ST[i] = min(ST[i], x); } else { int m = (l + r) / 2; range_chmin(L, R, x, i * 2 + 1, l, m); range_chmin(L, R, x, i * 2 + 2, m, r); } } void range_chmin(int L, int R, int x){ range_chmin(L, R, x, 0, 0, N); } }; struct heavy_light_decomposition{ vector p, sz, in, next; vector d1; vector d2; dual_segment_tree ST; heavy_light_decomposition(vector &p, vector>> &c): p(p){ int N = p.size(); sz = vector(N, 0); d1 = vector(N, 0); d2 = vector(N, 0); dfs1(c); in = vector(N, 0); next = vector(N, 0); int t = 0; dfs2(c, t); ST = dual_segment_tree(N); } void dfs1(vector>> &c, int v = 0){ sz[v] = 1; for (auto &P : c[v]){ int w = P.second; d1[w] = d1[v] + 1; d2[w] = d2[v] + P.first; dfs1(c, w); if (sz[w] > sz[c[v][0].second]){ swap(P, c[v][0]); } } } void dfs2(vector>> &c, int &t, int v = 0){ in[v] = t; t++; for (auto P : c[v]){ int w = P.second; if (P == c[v][0]){ next[w] = next[v]; } else { next[w] = w; } dfs2(c, t, w); } } int lca(int x, int y){ while (true){ if (in[x] > in[y]){ swap(x, y); } if (next[x] == next[y]){ return x; } y = p[next[y]]; } } int dist1(int x, int y){ return d1[x] + d1[y] - 2 * d1[lca(x, y)]; } long long dist2(int x, int y){ return d2[x] + d2[y] - 2 * d2[lca(x, y)]; } int operator [](int v){ return ST[in[v]]; } void path_chmin(int u, int v, int x){ int w = lca(u, v); while (next[u] != next[w]){ ST.range_chmin(in[next[u]], in[u] + 1, x); u = p[next[u]]; } ST.range_chmin(in[w] + 1, in[u] + 1, x); while (next[v] != next[w]){ ST.range_chmin(in[next[v]], in[v] + 1, x); v = p[next[v]]; } ST.range_chmin(in[w] + 1, in[v] + 1, x); } }; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int N, M; cin >> N >> M; vector> E(M); for (int i = 0; i < M; i++){ int A, B; cin >> A >> B; A--; B--; E[i] = make_pair(A, B); } vector cost(M); cost[0] = 2; for (int i = 1; i < M; i++){ cost[i] = cost[i - 1] * 2 % MOD; } unionfind UF(N); vector span(M, false); vector>> E2(N); for (int i = 0; i < M; i++){ int A = E[i].first; int B = E[i].second; if (!UF.same(A, B)){ span[i] = true; UF.unite(A, B); E2[A].push_back(make_pair(cost[i], B)); E2[B].push_back(make_pair(cost[i], A)); } } vector p(N, -1); vector>> c(N); vector d(N, 0); queue q; q.push(0); while (!q.empty()){ int v = q.front(); q.pop(); for (auto P : E2[v]){ int w = P.second; if (w != p[v]){ p[w] = v; c[v].push_back(P); d[w] = d[v] + 1; q.push(w); } } } heavy_light_decomposition T(p, c); for (int i = 0; i < M; i++){ if (!span[i]){ int A = E[i].first; int B = E[i].second; T.path_chmin(A, B, i); } } vector T2(N); for (int i = 0; i < N; i++){ T2[i] = T[i]; } int Q; cin >> Q; for (int i = 0; i < Q; i++){ int x, y, z; cin >> x >> y >> z; x--; y--; z--; int a = E[z].first; int b = E[z].second; if (!span[z]){ cout << T.dist2(x, y) % MOD << "\n"; } else { int d1 = T.dist1(x, a) + T.dist1(b, y); int d2 = T.dist1(x, b) + T.dist1(a, y); int d3 = T.dist1(x, y); if (d1 + 1 != d3 && d2 + 1 != d3){ cout << T.dist2(x, y) % MOD << "\n"; } else { if (b == p[a]){ swap(a, b); } int mn = T2[b]; if (mn == INF){ cout << -1 << "\n"; } else { int c = E[mn].first; int d = E[mn].second; long long ans1 = T.dist2(x, c) + cost[mn] + T.dist2(d, y); long long ans2 = T.dist2(x, d) + cost[mn] + T.dist2(c, y); cout << min(ans1, ans2) % MOD << "\n"; } } } } }