#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2005;
constexpr int M = 1e6 + 5;
int n, m, q, tot;
int a[N][N];
int b[N][N];
char str[N * 2];
int belong[N], color;
int p[N];
struct Edge
{
int next, to;
} edge[M];
int head[N], num_edge;
inline void add_edge(int from, int to)
{
from = p[from];
to = p[to];
if (from == to)
return;
edge[++num_edge].next = head[from];
edge[num_edge].to = to;
head[from] = num_edge;
// printf("nmsl%d %d\n", from, to);
}
int dfn[N], low[N], dfstime;
int st[N], top;
inline void tarjan(int u)
{
st[++top] = u;
dfn[u] = low[u] = ++dfstime;
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (!belong[v])
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
{
belong[u] = ++color;
while (st[top] != u)
belong[st[top--]] = color;
--top;
}
}
vector<int> g[N];
bitset<N> dp[N];
int in[N];
struct node
{
int l, r, c, id;
inline bool operator<(const node &rhs) const
{
return c < rhs.c;
}
} c[M];
bool answer[M];
inline void work()
{
cin >> n >> m >> q;
for (int i = 1; i <= n; ++i)
belong[i] = p[i] = i;
color = n;
for (int i = 1; i <= m; ++i)
{
cin >> str;
for (int j = 0; j < n; ++j)
a[i][j + 1] = (str[j * 2] - '0') * 50 + (str[j * 2 + 1] - '0');
for (int j = 1; j <= n; ++j)
b[i][j] = 0;
for (int j = 1; j <= n; ++j)
b[i][a[i][j]]++;
}
for (int i = 1; i <= q; ++i)
{
cin >> str;
c[i].l = (str[0] - '0') * 50 + (str[1] - '0');
c[i].r = (str[2] - '0') * 50 + (str[3] - '0');
c[i].c = (str[4] - '0') * 50 + (str[5] - '0');
c[i].id = i;
}
sort(c + 1, c + 1 + q);
int now = 1;
while (now <= q && c[now].c == 0)
{
int l = c[now].l, r = c[now].r, id = c[now].id;
answer[id] = (l == r);
++now;
}
for (int T = 1; T <= m; ++T)
{
// printf("%d\n", T);
// for (int i = 1; i <= tot; ++i)
// printf(" %d", head[i]);
// putchar('\n');
int where = 0;
for (int i = 1; i <= n; ++i)
if (!b[T][i])
{
if (where)
{
where = -1;
break;
}
else
where = i;
}
if (where != -1)
{
for (int u = 1, v; u <= n; ++u)
{
v = a[T][u];
if (!where)
add_edge(u, v);
else if (b[T][v] == 2)
add_edge(u, where);
}
}
tot = color;
color = 0;
for (int i = 1; i <= tot; ++i)
belong[i] = 0;
for (int i = 1; i <= tot; ++i)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; ++i)
p[i] = belong[p[i]];
for (int u = 1; u <= tot; ++u)
{
// printf("%d\n", u);
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (belong[u] == belong[v])
continue;
g[belong[v]].push_back(belong[u]);
++in[belong[u]];
}
}
queue<int> que;
for (int i = 1; i <= color; ++i)
{
dp[i].reset();
dp[i][i] = true;
if (!in[i])
que.push(i);
}
while (!que.empty())
{
int u = que.front();
que.pop();
for (auto v : g[u])
{
dp[v] |= dp[u];
if (!--in[v])
que.push(v);
}
}
while (now <= q && c[now].c == T)
{
int l = c[now].l, r = c[now].r, id = c[now].id;
// printf("%d %d %d\n", now, p[l], p[r]);
answer[id] = dp[p[l]][p[r]];
++now;
}
num_edge = dfstime = 0;
for (int i = 1; i <= tot; ++i)
head[i] = dfn[i] = low[i] = 0;
// printf("%d\n", tot);
// for (int i = 1; i <= n; ++i)
// printf("%d ", head[i]);
// putchar('\n');
for (int u = 1; u <= color; ++u)
{
for (int v : g[u])
{
edge[++num_edge].next = head[v];
edge[num_edge].to = u;
head[v] = num_edge;
}
g[u].clear();
}
}
for (int i = 1; i <= tot; ++i)
head[i] = 0;
num_edge = color = 0;
for (int i = 1; i <= q; ++i)
cout << answer[i];
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
work();
return 0;
}