最小生成树上倍增询问裸的。
const int maxn = 2e5 + 5;
int n, m, q;
//图
struct Edge {
int u, v;
ll cost;
bool operator < (const Edge &rhs) const {
return cost < rhs.cost;
}
}e[maxn];
map mp;
//最小生成树
int fa[maxn];
vector vc[maxn];
ll mst;
//树上倍增
int f[maxn][20], T, d[maxn];
ll dis[maxn][20];
int getf(int v) {
return v == fa[v] ? v : fa[v] = getf(fa[v]);
}
void kruscal() {
rep(i, 1, n) fa[i] = i;
sort(e + 1, e + 1 + m);
rep(i, 1, m) {
int t = getf(e[i].u), p = getf(e[i].v);
if (t != p) {
int u = e[i].u, v = e[i].v;
vc[u].push_back(v);
vc[v].push_back(u);
mst += e[i].cost;
fa[t] = p;
}
}
}
void bfs() {
T = (int)(log(n) / log(2)) + 1;
queue Q;
Q.push(1), d[1] = 1;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (auto y : vc[x]) {
if (d[y]) continue;
Q.push(y);
f[y][0] = x;
d[y] = d[x] + 1;
dis[y][0] = mp[P(y, x)];
rep(i, 1, T) {
f[y][i] = f[f[y][i - 1]][i - 1];
dis[y][i] = max(dis[f[y][i - 1]][i - 1], dis[y][i - 1]);
}
}
}
}
ll lca(int x, int y) {
ll ret = 0;
if (d[x] > d[y]) swap(x, y);
irep(i, T, 0)
if (d[f[y][i]] >= d[x]) {
ret = max(ret, dis[y][i]);
y = f[y][i];
}
if (x == y) return ret;
irep(i, T, 0)
if (f[y][i] != f[x][i]) {
ret = max(ret, max(dis[y][i], dis[x][i]));
y = f[y][i], x = f[x][i];
}
return max(ret, max(dis[y][0], dis[x][0]));
}
int main() {
read(n), read(m);
rep(i, 1, m) {
read(e[i].u);
read(e[i].v);
read(e[i].cost);
mp[P(e[i].u, e[i].v)] = mp[P(e[i].v, e[i].u)] = e[i].cost;
}
kruscal();
bfs();
for (read(q); q; q--) {
int u, v;
read(u), read(v);
writeln(mst - lca(u, v) + mp[P(u, v)]);
}
return 0;
}