#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10, M = 3e5 + 10;
struct Edge{
int u, v, w;
bool operator< (const Edge& e) const{
return w > e.w;
}
}edges[M];
int n, m, q;
int p[N];
int depth[N];
int fa[N][31], cost[N][31];
bool visit[N];
vector<int> g[N]; // 存储最大生成树的每个节点的所有出边
vector<int> c[N]; // 存储每个出边对应的值
int find(int x)
{
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
void kruskal()
{
for (int i = 0; i < m; i++) {
int u = edges[i].u, v = edges[i].v, w = edges[i].w;
int a = find(u), b = find(v);
if (a == b) continue;
p[a] = b;
g[u].push_back(v);
g[v].push_back(u);
c[u].push_back(w);
c[v].push_back(w);
}
}
void dfs(int u, int father)
{
visit[u] = true;
fa[u][0] = father;
depth[u] = depth[father] + 1;
for (int i = 1; i < 31; i++) {
fa[u][i] = fa[fa[u][i - 1]][i - 1]; //第 2^i 的祖先节点是第 2^(i-1) 的祖先节点的第2^(i-1) 的祖先节点。
cost[u][i] = min(cost[u][i - 1], cost[fa[u][i - 1]][i - 1]); // 稳定性为每一半的最小值
}
// 遍历子节点进行dfs
int sz = g[u].size();
for (int i = 0; i < sz; i++) {
if (g[u][i] == father) continue;
cost[g[u][i]][0] = c[u][i];
dfs(g[u][i], u);
}
}
int lca(int x, int y)
{
if (depth[x] > depth[y]) swap(x, y);
int h = depth[y] - depth[x];
int ans = 0x3f3f3f3f; // 初始化为无穷大
for (int i = 0; h != 0; i++, h >>= 1) {
if (h & 1) {
ans = min(ans, cost[y][i]);
y = fa[y][i];
}
}
if (y == x) return ans;
// 从上往下,找到第一个不是它们公共祖先的两个点
for (int i = 30; i >= 0 && y != x; i--) {
if (fa[x][i] != fa[y][i]) {
ans = min(ans, cost[x][i]);
ans = min(ans, cost[y][i]);
x = fa[x][i], y = fa[y][i];
}
}
// 最后一次更新
ans = min(ans, cost[x][0]);
ans = min(ans, cost[y][0]);
return ans;
}
int main()
{
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
edges[i].u = u, edges[i].v = v, edges[i].w = w;
}
sort(edges, edges + m);
kruskal();
// 遍历所有连通分量
for (int i = 1; i <= n; i++) {
if (!visit[i]) dfs(i, 0);
}
while (q--) {
int x, y;
cin >> x >> y;
if (find(x) != find(y)) printf("-1\n"); // 属于两个不同的连通块
else printf("%d\n", lca(x, y));
}
return 0;
}