#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
const int MAXM = 200005;
// Static Adjacency List
int head[MAXN], to[MAXM], nxt[MAXM], wt[MAXM], edge_cnt;
void add_edge(int u, int v, int w) {
to[++edge_cnt] = v; wt[edge_cnt] = w; nxt[edge_cnt] = head[u]; head[u] = edge_cnt;
}
// HLD Arrays
int parent[MAXN], depth[MAXN], heavy[MAXN], head_path[MAXN], pos[MAXN], sz[MAXN], weight_to_parent[MAXN], root_id[MAXN], cur_pos;
int tree[MAXN * 4]; // Segment Tree
// First DFS: Calculate size, heavy child, and depth
void dfs_sz(int u, int p, int d, int r) {
sz[u] = 1; parent[u] = p; depth[u] = d; root_id[u] = r;
heavy[u] = -1;
int max_sz = 0;
for (int i = head[u]; i; i = nxt[i]) {
if (to[i] != p) {
weight_to_parent[to[i]] = wt[i];
dfs_sz(to[i], u, d + 1, r);
sz[u] += sz[to[i]];
if (sz[to[i]] > max_sz) {
max_sz = sz[to[i]];
heavy[u] = to[i];
}
}
}
}
// Second DFS: Path decomposition
void dfs_hld(int u, int h) {
head_path[u] = h;
pos[u] = ++cur_pos;
if (heavy[u] != -1) dfs_hld(heavy[u], h);
for (int i = head[u]; i; i = nxt[i]) {
if (to[i] != parent[u] && to[i] != heavy[u]) {
dfs_hld(to[i], to[i]);
}
}
}
// Segment Tree: Point Update and Range Max Query
void update(int node, int start, int end, int idx, int val) {
if (start == end) { tree[node] = val; return; }
int mid = (start + end) / 2;
if (idx <= mid) update(2 * node, start, mid, idx, val);
else update(2 * node + 1, mid + 1, end, idx, val);
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
int query_tree(int node, int start, int end, int l, int r) {
if (r < start || end < l) return 0;
if (l <= start && end <= r) return tree[node];
int mid = (start + end) / 2;
return max(query_tree(2 * node, start, mid, l, r), query_tree(2 * node + 1, mid + 1, end, l, r));
}
// HLD Query: Max edge on path between u and v
int query_path(int u, int v, int n) {
if (root_id[u] != root_id[v]) return 2e9 + 7;
int res = 0;
while (head_path[u] != head_path[v]) {
if (depth[head_path[u]] < depth[head_path[v]]) swap(u, v);
res = max(res, query_tree(1, 1, n, pos[head_path[u]], pos[u]));
u = parent[head_path[u]];
}
if (u == v) return res;
if (depth[u] > depth[v]) swap(u, v);
// pos[u]+1 because we are querying edges (stored at child nodes)
res = max(res, query_tree(1, 1, n, pos[u] + 1, pos[v]));
return res;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
int n, m, u_queries; cin >> n >> m >> u_queries;
for (int i = 0; i < m; i++) {
int u, v, t; cin >> u >> v >> t;
add_edge(u, v, t); add_edge(v, u, t);
}
for (int i = 1; i <= n; i++) {
if (!depth[i]) {
dfs_sz(i, i, 1, i);
dfs_hld(i, i);
}
}
for (int i = 1; i <= n; i++) {
if (parent[i] != i) update(1, 1, n, pos[i], weight_to_parent[i]);
}
while (u_queries--) {
int a, b, p; cin >> a >> b >> p;
if (query_path(a, b, n) <= p) cout << "TAIP\n";
else cout << "NE\n";
}
return 0;
}