解法:我们发现,构建一个最大生成树,就是最优的运输方案,可以使用Kruskal算法,通过并查集实现最大生成树的构建。对于q次询问,每一次可以通过lca的方法在O(logn)时间内找到答案,如果x,y不在一个连通分量里面,输出-1,否则跑一遍x,y的lca即可。
#include<bits/stdc++.h>
using namespace std;
int n, m, q;
struct node {
int u, v;
int val;
}edge[50020];
bool cmp(const struct node &a, const struct node &b){
return a.val > b.val;
}
int f[10010];
int tot = 0;
int root = 0;
int find(int x){
return (f[x] == x ? x : f[x] = find(f[x]));
}
void Union(int x, int y){
int fx = find(x), fy = find(y);
if(fx != fy){
f[fx] = fy;
}
}
int head[200010];
int cnt = 0;
struct road{
int to;
int val;
int nxt;
}E[200010];
void add(int u, int v, int k){
E[++cnt].to = v;
E[cnt].val = k;
E[cnt].nxt = head[u];
head[u] = cnt;
}
void kusk(){
for(int i = 0; i <= n+1; i++){
f[i] = i;
}
for(int i = 1; i <= m; i++){
if(find(edge[i].u) == find(edge[i].v)){
continue;
}
Union(edge[i].u, edge[i].v);
add(edge[i].u, edge[i].v, edge[i].val);//建立树
add(edge[i].v, edge[i].u, edge[i].val);
if(++tot == n-1){
break;
}
}
//cout << "ok!\n";
}
//用来lca
int fa[200010][27];
int dep[200010];
int w[200010][27];
int vis[200010];
void dfs(int u, int d){
if(vis[u])
return ;
vis[u] = 1;
dep[u] = d;
for(int i = head[u]; ~i; i = E[i].nxt){
int v = E[i].to;
if(v == fa[u][0])
continue;
int k = E[i].val;
fa[v][0] = u;
w[v][0] = k;
dfs(v, d+1);
}
}
void build(){
for(int i = 1; i <= n; i++){
if(!vis[i]){
dep[i] = 1;
fa[i][0] = i;
w[i][0] = 1e9+7;//可能有多棵树
dfs(i, 1);
}
}
for(int k = 1; k <= 20; k++){
for(int i = 1; i <= n; i++){
//cout << fa[i][k-1] << "\n";
fa[i][k] = fa[fa[i][k-1]][k-1];
w[i][k] = min(w[i][k-1], w[fa[i][k-1]][k-1]);
}
}
//cout << "ok!\n";
}
int lca(int x, int y){
if(dep[x] > dep[y]){
swap(x, y);
}
int tx = x, ty = y;
int dx = dep[x], dy = dep[y];
int ans = 1e9 + 7;
for(int d = dy - dx, i = 0; d; d >>= 1, i++){
if(d & 1){
ans = min(ans, w[ty][i]);
ty = fa[ty][i];
}
}
//cout << tx << " " << ty << "\n";
if(tx == ty){
return ans;
}
for(int i = 20; i >= 0; i--){
if(fa[tx][i] != fa[ty][i]){
ans = min(ans, min(w[tx][i], w[ty][i]));
tx = fa[tx][i];
ty = fa[ty][i];
}
}
ans = min(ans, min(w[tx][0], w[ty][0]));
return ans;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i++){
cin >> edge[i].u >> edge[i].v >> edge[i].val;
//cout << "ok!\n";
}
sort(edge+1, edge+1+m, cmp);
memset(head, -1, sizeof head);
kusk();
build();
cin >> q;
while(q--){
int x, y;
cin >> x >> y;
//cout << find(x) << " " << find(y) << "\n";
if(find(x) != find(y)){
cout << -1 << "\n";
}
else{
cout << lca(x, y) << "\n";
}
}
return 0;
}