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.util.*;

public class Main{
    
    static int n,m;
    static int[][] vmax;
    static List<Edge>[] mst;
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int inf = (int)1e9;
        
        n = Integer.parseInt(sc.next());
        m = Integer.parseInt(sc.next());
        
        Kruskal kr = new Kruskal(n);
        for(int i=0; i<m; i++){
            int a = Integer.parseInt(sc.next())-1;
            int b = Integer.parseInt(sc.next())-1;
            int c = Integer.parseInt(sc.next());
            kr.addEdge(a, b, c);
        }
        
        long sum = kr.kruskal();
        mst = kr.getMST();
        
        vmax = new int[n][n];
        for(int i=0; i<n; i++){
            maxv(i);
        }
        
        int q = Integer.parseInt(sc.next());
        for(int i=0; i<q; i++){
            int s = Integer.parseInt(sc.next())-1;
            int t = Integer.parseInt(sc.next())-1;
            System.out.println(sum - vmax[s][t]);
        }
    }
    
    public static void maxv(int s){
        ArrayDeque<Integer> q = new ArrayDeque<>();
        q.addLast(s);
        boolean[] used = new boolean[n];
        while(q.size() != 0){
            int now = q.pollFirst();
            used[now] = true;
            for(int i=0; i<mst[now].size(); i++){
                Edge e = mst[now].get(i);
                if(!used[e.to]){
                    int tmp = Math.max(vmax[s][now], e.cost);
                    vmax[s][e.to] = Math.max(vmax[s][e.to], tmp);
                    q.add(e.to);
                }
            }
        }
    }
}

class Kruskal{
    private int n;
    private List<Edge> edge;
    private List<Edge>[] mst;
    private UnionFind uf;
    
    public Kruskal(int n){
        this.n = n;
        edge = new ArrayList<>();
        mst = new List[n];
        for(int i=0; i<n; i++){
            mst[i] = new ArrayList<>();
        }
        uf = new UnionFind(n);
    }
    
    public void addEdge(int from, int to, int cost){
        edge.add(new Edge(from, to, cost));
    }
    
    public long kruskal(){
        long sum = 0;
        Collections.sort(edge);
        for(int i=0; i<edge.size(); i++){
            Edge e = edge.get(i);
            if(uf.unite(e.from, e.to)){
                mst[e.from].add(new Edge(e.from, e.to, e.cost));
                mst[e.to].add(new Edge(e.to, e.from, e.cost));
                sum += e.cost;
            }
        }
        return sum;
    }
    
    public List<Edge>[] getMST(){
        return mst;
    }
}

class UnionFind{
    static int[] par;
    static int[] rank;
    
    public UnionFind(int n){
        par = new int[n];
        Arrays.fill(par, -1);
        rank = new int[n];
    }
    
    public static int find(int x){
        if(par[x] < 0){
            return x;
        }else{
            par[x] = find(par[x]);
            return par[x];
        }
    }
    
    public static boolean unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x==y) return false;
        
        if(rank[x]<rank[y]){
            par[x] = y;
        }else{
            par[y] = x;
            if(rank[x]==rank[y]) rank[x]++;
        }
        
        return true;
    }
    
    public static boolean same(int x, int y){
        return find(x)==find(y);
    }
}

 
class Edge implements Comparable<Edge>{
    public int from = 0;
    public int to = 0;
    public int cost = 0;
    
    public Edge(int from, int to, int cost) {
        this.from = from;
        this.to = to;
        this.cost = cost;
    }
    
    @Override
    public int compareTo(Edge o) {
        return this.cost - o.cost;
    }
}