思路
显然只有2*(n-1)条边可能被用到,所以先求最大生成树,然后由于两点间的路径是唯一的,所以进行LCA,并用
w
[
i
]
[
j
]
w[i][j]
w[i][j] 记录从第i个节点到它的
2
j
2^j
2j 祖先间的路径中最短的那条。
看起来简单但代码细节还蛮多的,注意更新w数组要在跳跃之前,以及最后不能直接返回
m
i
n
(
w
[
a
]
[
0
]
,
a
n
s
)
min(w[a][0],ans)
min(w[a][0],ans),还要考虑
w
[
b
]
[
0
]
w[b][0]
w[b][0]。
// Decline is inevitable,
// Romance will last forever.
#include <bits/stdc++.h>
using namespace std;
//#define mp make_pair
#define pii pair<int,int>
#define pb push_back
#define ll long long
#define LL long long
#define ld long double
#define endl '\n'
#define RE0 return 0
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define int long long
const int maxn = 1e4 + 10;
const int maxm = 6e4 + 10;
const int P = 1e9 + 7; //998244353
const int INF = 0x3f3f3f3f;
const double eps=1e-7;
int fa[maxn], n, m, ans, cnt;
struct Edge {
int u, v, w;
bool operator < (const Edge &a) const {
return w > a.w; // w > a.w 为最大生成树
}
}edge[maxm];
struct EDge {
int to, dis, next;
}edge2[maxm];
int p, head[maxn];
void add_edge(int u, int v, int w) {
++p;
edge2[p].to = v;
edge2[p].dis = w;
edge2[p].next = head[u];
head[u] = p;
}
int find(int x) {
if(x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void kruskal() {
sort(edge + 1, edge + 2*m + 1);
for(int i = 1; i <= n; i++)
fa[i] = i;
cnt = 0;
for(int i = 1; i <= m * 2; i++) {
int ev = find(edge[i].v);
int eu = find(edge[i].u);
if(ev == eu) continue;
add_edge(edge[i].v, edge[i].u, edge[i].w);
add_edge(edge[i].u, edge[i].v, edge[i].w);
fa[ev] = eu;
if(++cnt == n-1) {
// cout << ans << endl;
return;
}
}
}
int Log2[maxn], fat[maxn][30], dep[maxn];
int w[maxn][30];
bool vis[maxn];
void dfs(int cur, int fath = 0) {
if(vis[cur]) return;
vis[cur] = 1;
dep[cur] = dep[fath] + 1;
fat[cur][0] =fath;
w[cur][0] = INF;
for(int i = head[cur]; i; i = edge2[i].next) {
if(edge2[i].to == fath) {
w[cur][0] = edge2[i].dis;
break;
}
}
for(int i = 1; i <= Log2[dep[cur]]; i++){
fat[cur][i] = fat[fat[cur][i-1]][i-1];
w[cur][i] = min(w[cur][i-1], w[fat[cur][i-1]][i-1]);
}
for(int i = head[cur]; i; i = edge2[i].next)
dfs(edge2[i].to, cur);
}
int lca(int a, int b) {
if(find(a) != find(b)) return -1;
int ans = INF;
if(dep[a] > dep[b]) swap(a, b);
while(dep[a] != dep[b]) {
ans = min(w[b][Log2[dep[b]-dep[a]]], ans);
b = fat[b][Log2[dep[b]-dep[a]]];
}
if(a == b)
return ans;
for(int i = Log2[dep[a]]; i >= 0; i--)
if(fat[a][i] != fat[b][i]) {
ans = min(ans, w[a][i]);
ans = min(ans, w[b][i]);
a = fat[a][i];
b = fat[b][i];
}
ans = min(ans, w[a][0]);
ans = min(ans, w[b][0]);
return ans;
}
void init() {
for(int i = 1; i <= n; i++) {
dep[i] = 0;
head[i] = 0;
}
p = 0;
for(int i = 2; i <= n; i++)
Log2[i] = Log2[i / 2] + 1;
}
void solve() {
cin >> n >> m;
init();
int s;
for(int i = 1; i <= m; i++) {
int x, y, z;
cin >> x >> y >> z;
s = x;
edge[(i<<1)-1].u = x;
edge[(i<<1)-1].v = y;
edge[(i<<1)-1].w = z;
}
kruskal();
for(int i = 1; i <= n; i++) dfs(i);
int q;
cin >> q;
while(q--) {
int x, y;
cin >> x >> y;
cout << lca(x, y) << endl;
}
}
signed main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
solve();
RE0;
}