#include <fstream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
ifstream fin ("radiatie.in");
ofstream fout ("radiatie.out");
class Edge
{
public :
int a, b, c;
bool operator () (const Edge &nr1, const Edge &nr2) { return (nr1.c < nr2.c); }
} M[30010];
int n, m, k, nr_l;
int R[15010], T[15010]; // Rang, Tata
int W[15010], Level[15010], L[15010], L_Tata[15010], L_Level[15010], L_Dim[15010], L_Pos[15010], AINT[60010];
bool F[15010];
vector < pair < int, int > > G[15010], APM[15010], Path[15010];
int Find(int x)
{
int y, bos = x;
while (bos != T[bos]) bos = T[bos];
while (x != T[x])
{
y = T[x];
T[x] = bos;
x = y;
}
return bos;
}
void Unite(int x, int y)
{
if (R[x] < R[y])
{
T[x] = y;
R[y] += R[x];
}
else
{
T[y] = x;
R[x] += R[y];
}
}
void DFS(int node)
{
F[node] = true;
W[node] = 1;
int heavy_node = -1, leaf = 1;
for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
{
if (!F[it->first])
{
leaf = 0;
Level[it->first] = Level[node] + 1;
DFS(it->first);
W[node] += W[it->first];
if (heavy_node < 0 || W[it->first] > W[heavy_node]) heavy_node = it->first;
}
}
if (leaf)
{
nr_l ++;
L[node] = nr_l;
L_Dim[nr_l] = 1;
for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
{
if (Level[it->first] < Level[node])
{
Path[nr_l].push_back( { node, it->second } );
break;
}
}
}
else
{
int nice = 0;
L[node] = L[heavy_node];
L_Dim[L[node]] += 1;
for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
{
if (Level[it->first] < Level[node])
{
Path[L[node]].push_back( { node, it->second } );
nice = 1;
break;
}
}
if (!nice) Path[L[node]].push_back( { node, 0 } );
for (vector < pair < int, int > > :: iterator it = APM[node].begin(); it != APM[node].end(); it ++)
{
if (it->first != heavy_node && Level[it->first] > Level[node])
{
L_Tata[L[it->first]] = node;
L_Level[L[it->first]] = Level[node];
}
}
}
}
inline int Maxim(int const &a, int const &b)
{
if (a > b) return a;
return b;
}
void Build_Tree(int node, int left, int right, int decalaj, int lant)
{
if (left == right)
{
AINT[node + decalaj] = Path[lant][left - 1].second;
}
else
{
int mid = (left + right) / 2;
Build_Tree(node * 2, left, mid, decalaj, lant);
Build_Tree(node * 2 + 1, mid + 1, right, decalaj, lant);
AINT[node + decalaj] = Maxim(AINT[node * 2 + decalaj], AINT[node * 2 + 1 + decalaj]);
}
}
int Query(int node, int left, int right, int a, int b, int decalaj)
{
if (a <= left && right <= b)
{
return AINT[node + decalaj];
}
else
{
int mid = (left + right) / 2, ret1 = 0, ret2 = 0;
if (a <= mid) ret1 = Query(node * 2, left, mid, a, b, decalaj);
if (b > mid) ret2 = Query(node * 2 + 1, mid + 1, right, a, b, decalaj);
return Maxim(ret1, ret2);
}
}
int main()
{
fin >> n >> m >> k;
for (int i = 1; i <= m; i ++)
{
fin >> M[i].a >> M[i].b >> M[i].c;
G[M[i].a].push_back( { M[i].b, M[i].c } );
G[M[i].b].push_back( { M[i].a, M[i].c } );
}
sort(M + 1, M + 1 + m, Edge());
for (int i = 1; i <= n; i ++)
{
R[i] = 1;
T[i] = i;
}
for (int i = 1; i <= m; i ++)
{
int f1 = Find(M[i].a);
int f2 = Find(M[i].b);
if (f1 != f2)
{
Unite(f1, f2);
APM[M[i].a].push_back( { M[i].b, M[i].c } );
APM[M[i].b].push_back( { M[i].a, M[i].c } );
}
}
Level[1] = 1;
DFS(1);
for (int i = 1; i <= nr_l; i ++)
{
reverse(Path[i].begin(), Path[i].end());
if (i > 1) L_Pos[i] = L_Pos[i - 1] + L_Dim[i - 1] * 4;
Build_Tree(1, 1, L_Dim[i], L_Pos[i], i);
}
for (int a, b, i = 1; i <= k; i ++)
{
fin >> a >> b;
int sol = 0;
while (L[a] != L[b])
{
if (L_Level[L[a]] < L_Level[L[b]]) a ^= b ^= a ^= b;
sol = Maxim(sol, Query(1, 1, L_Dim[L[a]], 1, Level[a] - L_Level[L[a]], L_Pos[L[a]]));
a = L_Tata[L[a]];
}
if (Level[a] > Level[b]) a ^= b ^= a ^= b;
sol = Maxim(sol, Query(1, 1, L_Dim[L[a]], Level[a] - L_Level[L[a]] + 1, Level[b] - L_Level[L[a]], L_Pos[L[a]]));
fout << sol << '\n';
}
fout.close();
return 0;
}