Problem:
Score : 700 points

Problem Statement

Takahashi found an undirected connected graph with N vertices and M edges. The vertices are numbered 1 through N. The i-th edge connects vertices a_i and b_i, and has a weight of c_i.

He will play Q rounds of a game using this graph. In the i-th round, two vertices S_i and T_i are specified, and he will choose a subset of the edges such that any vertex can be reached from at least one of the vertices S_i or T_i by traversing chosen edges.

For each round, find the minimum possible total weight of the edges chosen by Takahashi.

Constraints

1 ≦ N ≦ 4,000

1 ≦ M ≦ 400,000

1 ≦ Q ≦ 100,000

1 ≦ a_i,b_i,S_i,T_i ≦ N

1 ≦ c_i ≦ 10^{9}

a_i \neq b_i

S_i \neq T_i

The given graph is connected.

Partial Scores

In the test set worth 200 points, Q = 1.

In the test set worth another 300 points, Q ≦ 3000.

Input

The input is given from Standard Input in the following format:

N M
a_1 b_1 c_1
a_2 b_2 c_2
:
a_M b_M c_M
Q
S_1 T_1
S_2 T_2
:
S_Q T_Q

Output

Print Q lines. The i-th line should contain the minimum possible total weight of the edges chosen by Takahashi.

Sample Input 1

4 3
1 2 3
2 3 4
3 4 5
2
2 3
1 4

Sample Output 1

8
7

We will examine each round:

In the 1-st round, choosing edges 1 and 3 achieves the minimum total weight of 8.

In the 2-nd round, choosing edges 1 and 2 achieves the minimum total weight of 7.

Sample Input 2

4 6
1 3 5
4 1 10
2 4 6
3 2 2
3 4 5
2 1 3
1
2 3

Sample Output 2

8

This input satisfies the additional constraints for both partial scores.

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Memory Limit Exceeded)

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

public class Main implements Runnable {
	public static void main(String[] args) {
		new Thread(null, new Main(), "", Runtime.getRuntime().maxMemory()).start();
	}

	public void run() {
		solver();
	}

	class DJSet {
		int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		void union(int x, int y) {
			x = root(x);
			y = root(y);
			if (x == y)
				return;
			if (upper[x] < upper[y]) {
				x ^= y;
				y ^= x;
				x ^= y;
			}
			upper[y] += upper[x];
			upper[x] = y;
		}
	}

	class Edge implements Comparable<Edge> {
		int u, v;
		int cost;

		public Edge(int u_, int v_, int cost_) {
			u = u_;
			v = v_;
			cost = cost_;
		}

		@Override
		public int compareTo(Edge arg0) {
			return Integer.compare(cost, arg0.cost);
		}
	}

	int[][] max;

	void dfs(int cur, int par, int src, int ma, ArrayList<Edge>[] g) {
		max[src][cur] = Math.max(max[src][cur], ma);
		for (Edge e : g[cur]) {
			if (e.v == par)
				continue;
			dfs(e.v, cur, src, Math.max(ma, e.cost), g);
		}
	}

	void solver() {
		Scanner sc = new Scanner(System.in);
		int N = Integer.parseInt(sc.next());
		int M = Integer.parseInt(sc.next());
		ArrayList<Edge>[] g = new ArrayList[N];
		int[][] es = new int[M][3];
		for (int i = 0; i < g.length; ++i)
			g[i] = new ArrayList();
		for (int i = 0; i < M; ++i) {
			int u = Integer.parseInt(sc.next());
			int v = Integer.parseInt(sc.next());
			int c = Integer.parseInt(sc.next());
			--u;
			--v;
			es[i] = new int[] { u, v, c };
		}
		Arrays.sort(es, new Comparator<int[]>() {
			@Override
			public int compare(int[] arg0, int[] arg1) {
				return Integer.compare(arg0[2], arg1[2]);
			}
		});
		DJSet ds = new DJSet(N);
		long ans = 0;
		for (int[] e : es) {
			if (!ds.equiv(e[0], e[1])) {
				ans += e[2];
				g[e[0]].add(new Edge(e[0], e[1], e[2]));
				g[e[1]].add(new Edge(e[1], e[0], e[2]));
				ds.union(e[0], e[1]);
			}
		}

		System.gc();
		max = new int[N][N];
		for (int i = 0; i < N; ++i) {
			dfs(i, -1, i, 0, g);
		}
		PrintWriter pw = new PrintWriter(System.out);
		int Q = Integer.parseInt(sc.next());
		for (int i = 0; i < Q; ++i) {
			int s = Integer.parseInt(sc.next());
			int d = Integer.parseInt(sc.next());
			--s;
			--d;
			pw.println(ans - max[s][d]);
		}
		pw.close();
	}

	void tr(Object... objects) {
		System.out.println(Arrays.deepToString(objects));
	}
}