题意:n个点m条边,每条边有一个权值,有q个询问,每次询问两点间的一条路径,使得这条路径上权值最大的边最小。
思路:很容易想到最小瓶颈路,但是查询太多,会超时,可以预处理出最小生成树,则问题转化为一棵树上的两点间路径中权值最大的那条边,设这两点为u,v,可以得到dist(u,v)=max(dist(u,lca(u,v)),dist(v,lca(v,lca))),其中lca(u,v)表示u和v的最近公共祖先,用倍增的思想预处理出每个结点的2^i的祖先fa[u][i],然后在离线求出lca后顺便计算出答案即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
using namespace std;
const int maxn = 55000;
const int maxm = 1000000 + 10000;
//const int INF = 0x3f3f3f3f;
int n, m, dep[maxn];
int pnt[maxn], ans[maxn], fa[maxn][20], dist[maxn][20];
vector<int> G[maxn], W[maxn], query[maxn], num[maxn];
int u[maxm], v[maxm], w[maxm], p[maxn], r[maxm];
bool cmp(const int i, const int j) {
return w[i] < w[j];
}
int find(int x) {
return p[x] == x ? x : p[x] = find(p[x]);
}
int Kruscal() {
int ans = 0;
for(int i = 1; i <= n; i++) p[i] = i; //初始化并查集
for(int i = 0; i < m; i++) r[i] = i; //初始化边序号
sort(r, r+m, cmp);
for(int i = 0; i < m; i++) {
int e = r[i];
int x = find(u[e]), y = find(v[e]);
if(x != y) {
ans += w[e];
p[x] = y;
G[u[e]].push_back(v[e]); G[v[e]].push_back(u[e]);
W[u[e]].push_back(w[e]); W[v[e]].push_back(w[e]);
}
}
return ans;
}
int solve(int u, int lca) {
int d = dep[u] - dep[lca];
//if(u==4&&lca==3) cout << dep[u] << " " << dep[lca] << endl;
int ans = 0;
for(int i = 17; i >= 0; i--) {
if((1<<i) <= d) {
d -= (1<<i);
ans = max(ans, dist[u][i]);
//if(u==4&&lca==3) cout << ans << endl;
u = fa[u][i];
}
}
return ans;
}
bool vis[maxn];
int find_pnt(int x) {
if(x == pnt[x]) return x;
return pnt[x] = find_pnt(pnt[x]);
}
void dfs(int u) {
vis[u] = 1; pnt[u] = u;
int sz1 = G[u].size();
for(int i = 0; i < sz1; i++) {
int v = G[u][i];
if(vis[v]) continue;
dep[v] = dep[u] + 1;
fa[v][0] = u;
dist[v][0] = W[u][i];
for(int j = 1; j <=17; j++) {
if(fa[v][j-1]) fa[v][j] = fa[ fa[v][j-1] ][j-1], dist[v][j] = max(dist[v][j-1], dist[ fa[v][j-1] ][j-1]);
else break;
}
dfs(v);
pnt[v] = u;
}
int sz2 = query[u].size();
for(int i = 0; i < sz2; i++) {
int v = query[u][i];
if(vis[v]) {
int lca = find_pnt(v); //cout << lca << endl;
ans[num[u][i]] = max(solve(u, lca), solve(v, lca));
}
}
}
void init() {
memset(vis, 0, sizeof(vis));
memset(fa, 0, sizeof(fa));
for(int i = 1; i <= n; i++) {
G[i].clear();
W[i].clear();
query[i].clear();
num[i].clear();
}
}
int main() {
//freopen("input.txt", "r", stdin);
int kase = 0;
while(cin >> n >> m) {
if(kase++) puts("");
init();
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &u[i], &v[i], &w[i]);
}
Kruscal();
int q; cin >> q;
for(int i = 0; i < q; i++) {
int x, y; scanf("%d%d", &x, &y);
query[x].push_back(y);
query[y].push_back(x);
num[x].push_back(i);
num[y].push_back(i);
}
dep[1] = 0;
dfs(1);
//cout << solve(4, 1) << endl;
for(int i = 0; i < q; i++) printf("%d\n", ans[i]);
}
return 0;
}