#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream f("radiatie.in");
ofstream g("radiatie.out");
const int INF = 2e9;
class minHeap
{
private:
struct heapElement
{
int key;
int value;
};
heapElement *harr;
int *pos;
int capacity;
int heapSize;
public:
minHeap(int cap, int maxKey);
~minHeap();
int parent(int node) {return node / 2;}
int leftChild(int node) {return node * 2;}
int rightChild(int node) {return node * 2 + 1;}
void heapifyUp(int node);
void heapifyDown(int node);
int getMin();
void extractMin();
void insertElement(int key, int value);
void decreaseKey(int key, int newValue);
};
minHeap :: minHeap(int cap, int maxKey)
{
harr = new heapElement[cap + 1];
pos = new int[maxKey + 1];
capacity = cap;
heapSize = 0;
}
minHeap :: ~minHeap()
{
delete[] harr;
delete[] pos;
}
void minHeap :: heapifyUp(int node)
{
while (node > 1 && harr[node].value < harr[parent(node)].value)
{
swap(pos[harr[node].key], pos[harr[parent(node)].key]);
swap(harr[node], harr[parent(node)]);
node = parent(node);
}
}
void minHeap :: heapifyDown(int node)
{
int child = 0;
do
{
child = 0;
if (leftChild(node) <= heapSize)
{
child = leftChild(node);
if (rightChild(node) <= heapSize && harr[rightChild(node)].value < harr[leftChild(node)].value)
child = rightChild(node);
if (harr[child].value >= harr[node].value)
child = 0;
}
if (child)
{
swap(pos[harr[node].key], pos[harr[child].key]);
swap(harr[node], harr[child]);
node = child;
}
}while (child);
}
int minHeap :: getMin()
{
return harr[1].key;
}
void minHeap :: extractMin()
{
if (!heapSize)
return;
pos[harr[1].key] = 0;
harr[1] = harr[heapSize];
pos[harr[1].key] = 1;
heapSize--;
heapifyDown(1);
}
void minHeap :: insertElement(int key, int value)
{
if (heapSize == capacity)
return;
heapSize++;
harr[heapSize].key = key;
harr[heapSize].value = value;
pos[key] = heapSize;
heapifyUp(heapSize);
}
void minHeap :: decreaseKey(int key, int newValue)
{
if (!pos[key])
return;
harr[pos[key]].value = newValue;
heapifyUp(pos[key]);
}
struct edge
{
int node;
int dist;
edge()
{
node = 0;
dist = 0;
}
edge(int _NODE, int _DIST)
{
node = _NODE;
dist = _DIST;
}
};
void prim(int V, const vector < edge > (&adj)[15001], vector < edge > (&newAdj)[15001])
{
bool *used = new bool[V + 1];
int *dist = new int[V + 1];
int *parent = new int[V + 1];
int root = 1;
for (int i=1; i<=V; i++)
{
used[i] = false;
dist[i] = INF;
}
used[root] = true;
for (auto it : adj[root])
{
dist[it.node] = it.dist;
parent[it.node] = root;
}
minHeap h(V, V);
for (int i=1; i<=V; i++)
if (i != root)
h.insertElement(i, dist[i]);
for (int i=1; i<V; i++)
{
int node = h.getMin();
h.extractMin();
used[node] = true;
newAdj[node].push_back(edge(parent[node], dist[node]));
newAdj[parent[node]].push_back(edge(node, dist[node]));
for (auto it : adj[node])
if (!used[it.node] && it.dist < dist[it.node])
{
dist[it.node] = it.dist;
parent[it.node] = node;
h.decreaseKey(it.node, it.dist);
}
}
delete[] used;
delete[] dist;
delete[] parent;
}
int n, m, k;
int log2[15001];
int depth[15001];
pair < int, int > dp[15001][14];
vector < edge > graph[15001];
vector < edge > tree[15001];
void dfs(const vector < edge > (&adj)[15001], int node, edge toParent, int d)
{
depth[node] = d;
dp[node][0].first = toParent.node;
dp[node][0].second = toParent.dist;
for (auto it : adj[node])
if (it.node != toParent.node)
dfs(adj, it.node, edge(node, it.dist), d + 1);
}
int maxDist(const vector < edge > (&adj)[15001], int node1, int node2)
{
if (node1 == node2)
return 0;
if (depth[node1] < depth[node2])
swap(node1, node2);
int maxDist = 0;
for (int i=log2[depth[node1]]; i>=0; i--)
if (depth[node1] - (1<<i) >= depth[node2])
{
maxDist = max(maxDist, dp[node1][i].second);
node1 = dp[node1][i].first;
}
if (node1 == node2)
return maxDist;
for (int i=log2[depth[node1]]; i>=0; i--)
if (dp[node1][i].first && dp[node1][i].first != dp[node2][i].first)
{
maxDist = max(maxDist, max(dp[node1][i].second, dp[node2][i].second));
node1 = dp[node1][i].first;
node2 = dp[node2][i].first;
}
maxDist = max(maxDist, max(dp[node1][0].second, dp[node2][0].second));
return maxDist;
}
int main()
{
f >> n >> m >> k;
for (int i=1; i<=m; i++)
{
int a, b, c; f >> a >> b >> c;
graph[a].push_back(edge(b, c));
graph[b].push_back(edge(a, c));
}
prim(n, graph, tree);
dfs(tree, 1, edge(0, 0), 0);
for (int i=1; (1<<i)<=n; i++)
for (int j=1; j<=n; j++)
{
dp[j][i].first = dp[dp[j][i-1].first][i-1].first;
dp[j][i].second = max(dp[j][i-1].second, dp[dp[j][i-1].first][i-1].second);
}
for (int i=2; i<=n; i++)
log2[i] = log2[i/2] + 1;
while (k--)
{
int x, y; f >> x >> y;
g << maxDist(tree, x, y) << "\n";
}
return 0;
}