#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <queue>
using namespace std;
struct Edge {
int u, v, length;
bool operator<(const Edge& other) const {
return length < other.length;
}
};
struct Query {
int x, y, index;
};
int findSet(int u, vector<int>& parent) {
if (u != parent[u])
parent[u] = findSet(parent[u], parent);
return parent[u];
}
void unionSets(int u, int v, vector<int>& parent, vector<int>& rank) {
int rootU = findSet(u, parent);
int rootV = findSet(v, parent);
if (rootU != rootV) {
if (rank[rootU] > rank[rootV]) {
parent[rootV] = rootU;
} else if (rank[rootU] < rank[rootV]) {
parent[rootU] = rootV;
} else {
parent[rootV] = rootU;
rank[rootU]++;
}
}
}
void dfs(int node, int parent, vector<vector<pair<int, int>>>& adj, vector<vector<int>>& maxEdge, vector<vector<int>>& up, vector<int>& depth) {
for (auto& [neighbor, weight] : adj[node]) {
if (neighbor != parent) {
up[neighbor][0] = node;
maxEdge[neighbor][0] = weight;
depth[neighbor] = depth[node] + 1;
dfs(neighbor, node, adj, maxEdge, up, depth);
}
}
}
void preprocess(int N, vector<vector<pair<int, int>>>& adj, vector<vector<int>>& maxEdge, vector<vector<int>>& up, vector<int>& depth) {
depth[1] = 0;
dfs(1, -1, adj, maxEdge, up, depth);
for (int j = 1; j < 20; ++j) {
for (int i = 1; i <= N; ++i) {
if (up[i][j - 1] != -1) {
up[i][j] = up[i][j - 1];
maxEdge[i][j] = max(maxEdge[i][j - 1], maxEdge[up[i][j - 1]][j - 1]);
}
}
}
}
int query(int u, int v, vector<vector<int>>& maxEdge, vector<vector<int>>& up, vector<int>& depth) {
if (depth[u] < depth[v])
swap(u, v);
int maxWeight = 0;
for (int i = 19; i >= 0; --i) {
if (depth[u] - (1 << i) >= depth[v]) {
maxWeight = max(maxWeight, maxEdge[u][i]);
u = up[u][i];
}
}
if (u == v)
return maxWeight;
for (int i = 19; i >= 0; --i) {
if (up[u][i] != up[v][i]) {
maxWeight = max({maxWeight, maxEdge[u][i], maxEdge[v][i]});
u = up[u][i];
v = up[v][i];
}
}
return max({maxWeight, maxEdge[u][0], maxEdge[v][0]});
}
int main() {
ifstream fin("radiatie.in");
ofstream fout("radiatie.out");
int N, M, K;
fin >> N >> M >> K;
vector<Edge> edges(M);
for (int i = 0; i < M; ++i) {
fin >> edges[i].u >> edges[i].v >> edges[i].length;
}
vector<Query> queries(K);
for (int i = 0; i < K; ++i) {
fin >> queries[i].x >> queries[i].y;
queries[i].index = i;
}
sort(edges.begin(), edges.end());
vector<int> parent(N + 1), rank(N + 1, 0);
for (int i = 1; i <= N; ++i)
parent[i] = i;
vector<vector<pair<int, int>>> adj(N + 1);
for (const auto& edge : edges) {
if (findSet(edge.u, parent) != findSet(edge.v, parent)) {
unionSets(edge.u, edge.v, parent, rank);
adj[edge.u].emplace_back(edge.v, edge.length);
adj[edge.v].emplace_back(edge.u, edge.length);
}
}
vector<vector<int>> up(N + 1, vector<int>(20, -1));
vector<vector<int>> maxEdge(N + 1, vector<int>(20, 0));
vector<int> depth(N + 1);
preprocess(N, adj, maxEdge, up, depth);
vector<int> results(K);
for (const auto& query : queries) {
results[query.index] = query(query.x, query.y, maxEdge, up, depth);
}
for (const auto& result : results) {
fout << result << "\n";
}
fin.close();
fout.close();
return 0;
}