这是一道$Kruskal$重构树的板子题,因为$Kruskal$重构树满足两节点的在原树上路径上边最大/小值为这两个点在重构树上的$LCA$的点权
#include <cstdio>
#include <algorithm>
using std::swap;
using std::sort;
typedef long long ll;
template <typename T>
inline void read (T &x) {
x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
const int N = 1e5 + 10, M = 5e4 + 10, LogN = 20;
int n, m, Q, x, y, tot, lim, fa[N << 1], poi[N];
int e_num, from[N << 1], to[N << 1], nxt[N << 1];//Edges
int dep[N], f[LogN][N << 1];//LCA
struct Edge {
int u, v, w;
inline bool operator < (const Edge &a) const { return w > a.w; }
} e[N << 1];
inline int find (int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inline void addEdge (int u, int v) {
to[++e_num] = v, nxt[e_num] = from[u], from[u] = e_num;
}
inline void Kruskal () {
sort(&e[1], &e[m + 1]);
for (int i = 1, cnt = 0; i <= m && cnt < n; ++i) {
int u = find(e[i].u), v = find(e[i].v);
if (u == v) continue;
poi[++tot] = e[i].w, fa[u] = fa[v] = tot;
addEdge(tot, u), addEdge(tot, v);
}
}
void dfs (int u) {
for (int i = from[u]; i; i = nxt[i]) {
int v = to[i]; dep[v] = dep[u] + 1;
f[0][v] = u, dfs(v);
}
}
inline int LCA (int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
int delta = dep[x] - dep[y];
for (int i = 0; i < LogN; ++i)
if ((1 << i) & delta)
x = f[i][x];
if (x == y) return poi[x];
for (int i = LogN - 1; i >= 0; --i)
if (f[i][x] != f[i][y])
x = f[i][x], y = f[i][y];
return poi[f[0][x]];
}
int main () {
read(n), read(m), tot = n, lim = n << 1;
for (int i = 1; i <= lim; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i)
read(e[i].u), read(e[i].v), read(e[i].w);
Kruskal(), read(Q);
for (int i = tot; i >= 1; --i)
if (!dep[i]) dep[i] = 1, dfs(i);
for (int i = 1; i < LogN; ++i)
for (int j = 1; j <= tot; ++j)
f[i][j] = f[i - 1][f[i - 1][j]];
while (Q--) {
read(x), read(y);
int fx = find(x), fy = find(y);
if (fx != fy) puts("-1");
else printf("%d
", LCA(x, y));
}
return 0;
}