#include<stdio.h>
#include<string.h>
#define Inf 0x3f3f3f3f
#define Nmax 15003
FILE*f=fopen("radiatie.in","r");
FILE*g=fopen("radiatie.out","w");
int H[Nmax],N; // H[i] - nodul aflat pe pozitia i in heap
int poz[Nmax]; // poz[i] - pozitia in heap a nodului i
int c[Nmax]; // c[i] - costul nodului i
int viz[Nmax];
int Nod[Nmax]; // Nod[i] - nodul de la care vine elementul de pe pozitia i
int n,m;
int nr,K;
struct Graf{int vf,cst; Graf *urm;};
Graf *G[Nmax];
inline int min(int x, int y)
{
if(x>y) return y;
else return x;
}
inline void add(int x, int y, int cst)
{
Graf *q;
q=new Graf;
q->vf = y;
q->cst = cst;
q->urm = G[x];
G[x]=q;
}
void read()
{
fscanf(f,"%d%d%d",&n,&m,&K);
int a,b,c;
while(m--)
{
fscanf(f,"%d%d%d",&a,&b,&c);
add(a,b,c); add(b,a,c);
}
}
inline void swap(int f, int t)
{
int aux;
aux=Nod[f]; Nod[f] = Nod[t]; Nod[t]=aux;
aux=poz[H[f]]; poz[H[f]]=poz[H[t]]; poz[H[t]]=aux;
aux=H[f]; H[f]=H[t]; H[t]=aux;
}
void downheap(int t) // duc in jos elementul de pe pozitia k
{
int f;
do
{
f=0;
if(2*t <= N) f=2*t;
if(2*t+1 <= N && c[H[f]] > c[H[2*t+1]]) f=2*t+1;
if(c[H[f]] > c[H[t]]) f=0;
if(f)
{
swap(t,f);
t=f;
}
}
while(f);
}
void upheap(int f)
{
int t=f/2;
while(t && c[H[t]] > c[H[f]])
{
swap(t,f);
t=t/2; f=f/2;
}
}
int s;
Graf *Arb[Nmax];
inline void insert(int x, int y, int cst)
{
Graf *q;
q=new Graf;
q->vf=y; q->cst=cst; q->urm=Arb[x];
Arb[x]=q;
}
void vezi()
{
Graf *q;
int i;
for(i=1;i<=n-1;++i)
{
fprintf(g,"\n%d: ",i);
for(q=Arb[i];q;q=q->urm)
fprintf(g,"(%d,%d) ",q->vf,q->cst);
}
}
void apm()
{
int i,p, nod;
memset(c,Inf,sizeof(c));
memset(poz,-1,sizeof(poz));
c[1]=0;
H[1] = 1;
poz[1] = 1;
Nod[1] = -1;
N=1;
Graf *q;
for(i=1;i<=n;++i)
{
p = H[1]; // introduc nodul p
nod = Nod[1]; // am muchia (nod,p)
if(i>1) insert(p,nod, c[p]); insert(nod,p, c[p]);
viz[p] = 1;
// elimin varful p din heap
H[1] = H[N];
Nod[1] = Nod[N];
poz[H[1]] = 1;
N--;
downheap(1);
//fac update pt nodurile care nu sunt in arbore
for(q=G[p];q;q=q->urm)
if(!viz[q->vf] && c[q->vf] > q->cst)
{
c[q->vf] = q->cst;
if(poz[q->vf] == -1)
{
N++;
poz[q->vf] = N;
Nod[N] = p;
H[N] = q->vf;
upheap(N);
}
else
{
Nod[poz[q->vf]] = p;
upheap(poz[q->vf]);
}
}
}
}
int euler[Nmax], timp[Nmax], nrp;
int pz[Nmax], tata[Nmax], cost[Nmax];
void dfs(int x, int niv, int t, int cst)
{
int ok=1;
viz[x]=1;
tata[x]=t;
cost[x]=cst;
euler[++nrp] = x;
pz[x] = nrp;
timp[nrp] = niv;
Graf *q;
for(q=Arb[x];q;q=q->urm)
if(!viz[q->vf])
{
ok=0;
dfs(q->vf, niv+1, x, q->cst);
euler[++nrp]=x;
timp[nrp]=niv;
}
}
int rmq[14][Nmax];
int log[Nmax];
void rmq_init(int n)
{
int i,j;
for(i=2;i<=n;++i) log[i] = log[i/2] + 1;
for(i=1;i<=n;++i) rmq[0][i] = i;
for(j=1;(1<<j)<=n;++j)
for(i=1;i<=n;++i)
{
rmq[j][i] = rmq[j-1][i];
if(timp[rmq[j][i]] > timp[rmq[j-1][i+(1<<(j-1))]])
rmq[j][i] = rmq[j-1][i+(1<<(j-1))];
}
}
inline int query(int x, int y)
{
int k=log[y-x+1];
int sol;
if(timp[rmq[k][x]] > timp[rmq[k][y-(1<<k)+1]])return rmq[k][y-(1<<k)+1];
return rmq[k][x];
}
inline int LCA(int x, int y)
{
int p1,p2, aux;
p1=pz[x];
p2=pz[y];
if(p2<p1) { aux=p1; p1=p2; p2=aux; }
int p=query(p1,p2); //returneaza pozitia elem minim dintre p1 si p2.
return euler[p];
}
inline int max(int x, int y) {return x>y?x:y;}
int drum(int f, int t)
{
int m=0;
while(f!=t)
{
if(cost[f] > m ) m=cost[f];
f=tata[f];
}
return m;
}
int main()
{
read();
apm(); // Creez arborele
memset(viz,0,sizeof(viz));
dfs(1,1,-1,0); // Creez parcurgerea euleriana si adancimea fiecarui nod+tata[]
rmq_init(nrp); // Calculez matricea rmq[][]
int x,y,sol,n1,n2;
// fprintf(g,"%d\n",LCA(1,6));
while(K--)
{
fscanf(f,"%d%d",&x,&y);
int nod = LCA(x,y);
n1 = drum(x, nod);
n2 = drum(y, nod);
sol=max(n1,n2);
fprintf(g,"%d\n",sol);
}
return 0;
}