#include <fstream>
#include <vector>
#include <algorithm>
#define IT vector< int > ::iterator
#define NODE (node+decalaj)
#define LeftSon (2*node)
#define RightSon (2*node+1)
#define In "radiatie.in"
#define Out "radiatie.out"
#define edge pair < int ,pair < int ,int > >
#define Nmax 15004
#define Mmax 30004
#define X second.first
#define Y second.second
#define cost first
using namespace std;
edge e[Mmax];
ifstream f(In);
ofstream g(Out);
vector< int > Tree[Nmax];
vector<int > el[Nmax];
int niv[Nmax], Root,m ;
int n, ans, L, v[Nmax], LantDim[Nmax];
int nr[Nmax],Lant[Nmax];
int LantFather[Nmax],LantSum[Nmax];
int pos[Nmax], nivFather[Nmax];
int Father[Nmax];
struct DisjointSets
{
inline void Buid()
{
for(int i = 1;i <= n; ++i)
Father[i] = i;
}
inline int Find(int node)
{
while(node!=Father[node])
node = Father[node];
return node;
}
inline void Union(const int x,const int y)
{
Father[x] = y;
}
};
DisjointSets S;
inline void APM()
{
sort(e+1,e+m+1);
int i ,x ,y;
S.Buid();
for(i = 1;i <= m; ++i)
{
x = S.Find(e[i].X) ;
y = S.Find(e[i].Y) ;
if(y != x)
{
S.Union(x,y);
Tree[y].push_back(x);
v[x] = e[i].cost;
}
}
}
class SegmentTree
{
public :
inline void Build(const int node,const int left,const int right,const int decalaj,int lant)
{
if(left == right )
{
aint[NODE] = v[el[lant][left]];
return ;
}
int middle = (left + right)>>1;
Build(LeftSon,left,middle,decalaj,lant);
Build(RightSon,middle+1,right,decalaj,lant);
aint[NODE] = max(aint[LeftSon+decalaj],aint[RightSon+decalaj]);
}
inline void Query(const int node,const int left,const int right,const int x ,const int y,const int decalaj)
{
if(x <= left && right <= y )
{
ans = max(ans,aint[NODE]);
return ;
}
int middle = (left + right)>>1;
if(x<=middle)
Query(LeftSon,left,middle,x,y,decalaj);
if(middle+1<=y)
Query(RightSon,middle+1,right,x,y,decalaj);
}
private :int aint[4*Nmax];
};
inline void Erase(const int node,const int Father)
{
IT it, del = Tree[node].end();
for(it = Tree[node].begin();it!=Tree[node].end(); ++it)
if(*it==Father)
del = it;
else
Erase(*it,node);
if(del!=Tree[node].end())
Tree[node].erase(del);
}
inline void DFS(const int node)
{
IT it;
bool frunza = 1;
int SonMAX = 0, lant;
nr[node] = 1;
for(it = Tree[node].begin(); it!= Tree[node].end(); ++it)
{
niv[*it] = niv[node]+1;
frunza = 0;
DFS(*it);
nr[node] += nr[*it];
if(nr[*it] > nr[SonMAX])
SonMAX= *it;
}
if(frunza)
{
++L;
Lant[node] = L;
LantDim[L] = 1;
el[L].push_back(node);
return ;
}
lant = Lant[SonMAX];
Lant[node] = lant;
++LantDim[lant];
el[lant].push_back(node);
for(it = Tree[node].begin(); it!= Tree[node].end(); ++it)
if(*it!=SonMAX)
{
LantFather[Lant[*it]] = node;
nivFather[Lant[*it]] = niv[node];
}
}
inline void Reverse(const int i)
{
int j,n = LantDim[i],m;
m = (n>>1)+ (n&1);
if(n==1)
pos[el[i][1]] = 1;
for(j = 1;j <= m; ++j)
{
swap(el[i][j],el[i][n-j+1]);
pos[el[i][j]] = j;
pos[el[i][n-j+1]] = n-j+1;
}
}
SegmentTree A;
int main()
{
int i,x, k, y;
f>>n >> m >> k;
for(i = 1;i <= n; ++i)
{
f>> e[i].X >> e[i].Y >>e[i].cost;
el[i].push_back(0);
}
APM();
for(i=1;i<=n;++i)
if(Father[i]==i)
{
Root = i;
break ;
}
Erase(Root,0);
niv[Root] = 1;
DFS(Root);
for(i = 1;i <= L; ++i)
{
Reverse(i);
if(i>1)
LantSum[i] = LantSum[i-1] + 4*LantDim[i-1];
A.Build(1,1,LantDim[i],LantSum[i],i);
}
for( ; k; --k)
{
f>> x >> y;
ans = 0;
while(true)
{
if(Lant[x]==Lant[y])
{
if(niv[x]>niv[y])
swap(x,y);
if(pos[x]==pos[y])
break;
A.Query(1,1,LantDim[Lant[x]],pos[y],pos[y],LantSum[Lant[x]]);
break;
}
if(nivFather[Lant[x]] < nivFather[Lant[y]])
swap(x,y);
A.Query(1,1,LantDim[Lant[x]],1,pos[x],LantSum[Lant[x]]);
x = LantFather[Lant[x]];
}
g<<ans<<"\n";
}
f.close();
g.close();
return 0;
}