#include <cstdio>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
#define cost first
#define son second
#define edge second
const int NMAX = 15005;
const int LOGMAX = 11;
multimap<int, pair<int, int> > Edges;
vector<pair<int, int> > Neighb[NMAX];
int Group[NMAX], n, m, k;
int Parent[NMAX][LOGMAX], Max[NMAX][LOGMAX];
int Depth[NMAX];
//int Start[NMAX], End[NMAX], Euler[NMAX], nEuler = 0;
//bool Used[NMAX];
void relabel(int bad, int good) {
int i;
for (i = 0; i < n; ++ i)
if (Group[i] == bad)
Group[i] = good;
}
void doKruskal() {
int i;
for (i = 0; i < n; ++ i)
Group[i] = i;
int nEdges;
multimap<int, pair<int, int> >::iterator mi;
for (mi = Edges.begin(), nEdges = 0; mi != Edges.end() && nEdges < n - 1; ++ mi)
if (Group[mi->edge.first] != Group[mi->edge.second]) {
relabel(Group[mi->edge.first], Group[mi->edge.second]);
++ nEdges;
Neighb[mi->edge.first].push_back(make_pair(mi->cost, mi->edge.second));
Neighb[mi->edge.second].push_back(make_pair(mi->cost, mi->edge.first));
}
}
void init() {
int i, j;
for (i = 0; i < n; ++ i)
for (j = 0; (1 << j) <= n; ++ j) {
Parent[i][j] = -1;
Max[i][j] = 0;
}
Depth[0] = 1;
for (i = 1; i < n; ++ i)
Depth[i] = -1;
}
void doDepthFirst(int curr) {
vector<pair<int, int> >::iterator vi;
for (vi = Neighb[curr].begin(); vi != Neighb[curr].end(); ++ vi)
if (Depth[vi->son] == -1) {
Parent[vi->son][0] = curr;
Max[vi->son][0] = vi->cost;
//printf("%d ", Max[vi->son][0]);
Depth[vi->son] = Depth[curr] + 1;
doDepthFirst(vi->son);
}
}
/*void doEulerTraversal(int curr) {
Used[curr] = true;
Start[curr] = End[curr] = nEuler;
Euler[nEuler ++] = curr;
vector<pair<int, int> >::iterator vi;
for (vi = Neighb[curr].begin(); vi != Neighb[curr].end(); ++ vi)
if (Used[vi->son] == false) {
doEulerTraversal(vi->son);
End[curr] = nEuler;
Euler[nEuler ++] = curr;
}
}*/
void getParents() {
int i, j;
for (j = 1; (1 << j) < n; ++ j)
for (i = 0; i < n; ++ i)
if (Parent[i][j - 1] != -1 && Parent[Parent[i][j - 1]][j - 1] != -1) {
Parent[i][j] = Parent[Parent[i][j - 1]][j - 1];
Max[i][j] = max(Max[i][j - 1], Max[Parent[i][j - 1]][j - 1]);
}
}
int query(int a, int b) {
int temp, ans = 0;
//printf("%d %d\n", a, b);
if (Depth[a] < Depth[b]) { // a e mai adanc in arbore si trebuie ridicat
temp = a;
a = b;
b = temp;
}
//printf("%d %d\n\n", a, b);
int log;
for (log = 0; (1 << log) <= Depth[a]; ++ log); // determin log a.i. 2^log <= Depth[a] si log maxim
-- log;
int j; // am nevoie de stramosul Depth[a] - Depth[b] al lui a
for (j = log; j >= 0; -- j)
if (Depth[a] - (1 << j) >= Depth[b]) {
ans = max(ans, Max[a][j]);
a = Parent[a][j];
}
if (a == b)
return ans;
for (j = log; j >= 0; -- j)
while (Parent[a][j] != -1 && Parent[a][j] == Parent[b][j]) { // stramosul comun e prea sus
ans = max(ans, Max[a][j]); // daca urc nodurile, trec prin muchiile respective => update pentru raspuns
ans = max(ans, Max[b][j]);
a = Parent[a][j], b = Parent[b][j]; // urc cele 2 noduri si injumatatesc intervalul de cautare
}
ans = max(ans, Parent[a][0]);
return ans;
}
int main() {
freopen("radiatie.in", "r", stdin);
freopen("radiatie.out", "w", stdout);
scanf("%d %d %d", &n, &m, &k);
int i, a, b, c;
for (i = 0; i < m; ++ i) {
scanf("%d %d %d", &a, &b, &c);
-- a, -- b;
Edges.insert(make_pair(c, make_pair(a, b)));
}
doKruskal();
init();
doDepthFirst(0);
getParents();
for (i = 0; i < k; ++ i) {
scanf("%d %d", &a, &b);
-- a, -- b;
printf("%d\n", query(a, b));
}
/*for (i = 0; i < n; ++ i)
printf("%d ", Depth[i]);*/
/*int j;
for (i = 0; i < n; ++ i) {
for (j = 0; j < 3; ++ j)
printf("%d ", Max[i][j]);
printf("\n");
}*/
return 0;
}