思路是先求一个最大生成树,两点之间用 lca 维护唯一路径并记录最小值。qwq
#include <bits/stdc++.h>
#define re register int
#define min(x, y) (x < y ? x : y)
using namespace std;
const int N = 1e5 + 10, M = 3e5 + 10, logN = 50, inf = 1e6;
struct Edge
{
int to, w, next;
}e[M];
int top, h[N], dep[N], fa[N][logN], w[N][logN];
struct edge
{
int x, y, w;
}g[M];
int idx, f[N];
int n, m, q, ans = inf;
bool vis[N];
bool cmp(edge i, edge j) { return i.w > j.w; }
inline void add(int x, int y, int w)
{
e[++ top] = {y, w, h[x]};
h[x] = top;
}
int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);
}
inline void kruskal()
{
for (re i = 1; i <= n; i ++) f[i] = i;
sort(g + 1, g + idx + 1, cmp);
for (re i = 1; i <= idx; i ++)
{
int x = g[i].x, y = g[i].y, w = g[i].w;
if (find(x) != find(y))
{
f[find(x)] = find(y);
add(x, y, w);
add(y, x, w);
}
}
return;
}
void dfs(int u)
{
vis[u] = true;
for (re i = h[u]; i; i = e[i].next)
{
int v = e[i].to;
if (!vis[v]) // u <- v
{
dep[v] = dep[u] + 1;
fa[v][0] = u;
w[v][0] = e[i].w;
// cout << v << ' ' << w[v][0] << "ikun\n";
dfs(v);
}
}
return;
}
inline void init()
{
memset(w, inf, sizeof(w));
for (re i = 1; i <= n; i ++)
if (!vis[i])
{
dep[i] = 1;
dfs(i);
}
for (re i = 1; i <= log(n); i ++)
for (re u = 1; u <= n; u ++)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
w[u][i] = min(w[u][i - 1], w[fa[u][i - 1]][i - 1]);
}
return;
}
inline int lca(int u, int v)
{
ans = inf;
if (dep[u] < dep[v]) swap(u, v);
for (re i = log2(n); i >= 0; i --)
if (dep[fa[u][i]] >= dep[v])
{
ans = min(ans, w[u][i]);
u = fa[u][i];
}
if (u == v) return ans;
for (re i = log2(n); i >= 0; i --)
if (fa[u][i] != fa[v][i])
{
ans = min(ans, min(w[u][i], w[v][i]));
u = fa[u][i], v = fa[v][i];
}
return ans = min(ans, min(w[u][0], w[v][0]));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m >> q;
for (re i = 1; i <= m; i ++)
{
int x, y, z; cin >> x >> y >> z;
g[++ idx] = {x, y, z};
}
kruskal();
init();
while (q --)
{
int x, y; cin >> x >> y;
if (find(x) != find(y)) cout << "-1\n";
else
cout << lca(x, y) << '\n';
}
return 0;
}