#include <bits/stdc++.h>
using namespace std;
int read()
{
int res = 0, bj = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') bj = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
return res * bj;
}
const int MAXN = 2005, MAXM = 1e6 + 5;
int tt, T;
int n, m, q; //n个牛棚, m个按钮
char s[MAXM];
struct Que {
int a, b, c;
int ans;
int id;
}que[MAXM];
int t[MAXN][MAXN];
bitset<MAXN> f[MAXN];
struct Edge {
int x, y;
}e1[MAXN * MAXN], e2[MAXN * MAXN]; //e2是temp数组
//e1保存的原图的边
vector<int> g[MAXN]; //染色图的边
int cnt1, cnt2;
vector<int> pos[MAXN]; //第i种染色对应的点
int in[MAXN]; //节点入度
int dfn[MAXN], low[MAXN], inx;
int stk[MAXN], top;
int vis[MAXN];
int scc, col[MAXN];
void tarjan(int u)
{
dfn[u] = low[u] = ++inx;
stk[++top] = u;
vis[u] = 1;
for (int v : g[u])
{
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u])
{
scc++;
int t;
do {
t = stk[top--];
vis[t] = 0;
for (int x : pos[t]) col[x] = scc;
} while (t != u);
}
}
void work(int K) //第K个按钮
{
//重置e1数组
for (int i = 1; i <= n; i++) in[i] = 0;
for (int i = 1; i <= n; i++) in[t[K][i]]++;
for (int i = 1; i <= n; i++)
if (in[i] >= 3) return; //入度>=3不符合条件
int sum2 = 0, p = 0; //入度为2的节点个数
for (int i = 1; i <= n; i++)
if (in[i] == 2) sum2++, p = i;
if (sum2 >= 2) return;
for (int i = 1; i <= cnt2; i++) e1[i] = e2[i];
cnt1 = cnt2;
cnt2 = 0;
if (sum2 == 1)
{
int x1 = 0, x2 = 0, y;
for (int i = 1; i <= n; i++)
if (t[K][i] == p) x1 = i;
for (int i = 1; i <= n; i++)
if (t[K][i] == p && i != x1) x2 = i;
for (int i = 1; i <= n; i++)
if (in[i] == 0) y = i;
e1[++cnt1] = (Edge){x1, y};
e1[++cnt1] = (Edge){x2, y};
}
else
{
for (int i = 1; i <= n; i++)
{
int x = i, y = t[K][i];
e1[++cnt1] = (Edge){x, y};
}
}
int last_scc = scc;
for (int i = 1; i <= last_scc; i++) g[i].clear();
for (int i = 1; i <= cnt1; i++)
{
int x = e1[i].x, y = e1[i].y;
if (col[x] != col[y])
{
g[col[x]].push_back(col[y]);
}
}
//tarjan清空
for (int i = 1; i <= last_scc; i++)
{
dfn[i] = low[i] = 0;
vis[i] = 0;
col[i] = 0;
}
inx = top = scc = 0;
for (int i = 1; i <= last_scc; i++)
if (!dfn[i]) tarjan(i);
//更新pos数组
for (int i = 1; i <= last_scc; i++) pos[i].clear();
for (int i = 1; i <= n; i++) pos[col[i]].push_back(i);
//更新g数组为topsort数组
for (int i = 1; i <= last_scc; i++) g[i].clear();
map<pair<int, int>, int> ma;
for (int i = 1; i <= cnt1; i++)
{
int x = e1[i].x, y = e1[i].y;
if (col[x] != col[y])
{
if (ma[make_pair(col[x], col[y])] == 1) continue;
g[col[y]].push_back(col[x]);
ma[make_pair(col[x], col[y])] = 1;
e2[++cnt2] = (Edge){x, y};
}
}
for (int i = 1; i <= scc; i++) in[i] = 0; //in数组清空
for (int i = 1; i <= scc; i++) f[i].reset();
for (int u = 1; u <= scc; u++)
for (int v : g[u]) in[v]++;
queue<int> q;
for (int i = 1; i <= scc; i++)
{
f[i].set(i);
if (in[i] == 0) q.push(i);
}
while (q.size())
{
int u = q.front();
q.pop();
for (int v : g[u])
{
f[v] |= f[u];
in[v]--;
if (in[v] == 0) q.push(v);
}
}
}
void solve()
{
n = read(), m = read(), q = read();
for (int i = 1; i <= m; i++)
{
scanf("%s", s + 1);
int len = strlen(s + 1);
for (int j = 1; j <= len; j += 2)
{
int x = s[j] - 48, y = s[j + 1] - 48;
t[i][(j + 1) / 2] = x * 50 + y;
}
}
for (int i = 1; i <= q; i++)
{
que[i].id = i;
scanf("%s", s + 1);
int x, y;
x = s[1] - 48, y = s[2] - 48;
que[i].a = x * 50 + y;
x = s[3] - 48, y = s[4] - 48;
que[i].b = x * 50 + y;
x = s[5] - 48, y = s[6] - 48;
que[i].c = x * 50 + y;
}
sort(que + 1, que + q + 1, [](Que A, Que B) {
return A.c < B.c;
});
scc = n;
for (int i = 1; i <= n; i++) pos[i].clear();
for (int i = 1; i <= n; i++)
{
pos[i].push_back(i);
col[i] = i;
f[i].reset(); //记得重置f数组!!!
f[i].set(i);
}
cnt1 = cnt2 = 0;
int j = 1;
for (int i = 1; i <= q; i++)
{
while (j <= que[i].c) work(j), j++;
int a = que[i].a, b = que[i].b;
que[i].ans = f[col[a]][col[b]];
}
sort(que + 1, que + q + 1, [](Que A, Que B) {
return A.id < B.id;
});
for (int i = 1; i <= q; i++) cout << que[i].ans;
cout << "\n";
}
int main()
{
int tt = read();
while (tt--) solve();
return 0;
} #include <bits/stdc++.h>
using namespace std;
int read()
{
int res = 0, bj = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') bj = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
return res * bj;
}
const int MAXN = 2005, MAXM = 1e6 + 5;
int tt, T;
int n, m, q; //n个牛棚, m个按钮
char s[MAXM];
struct Que {
int a, b, c;
int ans;
int id;
}que[MAXM];
int t[MAXN][MAXN];
bitset<MAXN> f[MAXN];
struct Edge {
int x, y;
}e1[MAXN * MAXN], e2[MAXN * MAXN]; //e2是temp数组
//e1保存的原图的边
vector<int> g[MAXN]; //染色图的边
int cnt1, cnt2;
vector<int> pos[MAXN]; //第i种染色对应的点
int in[MAXN]; //节点入度
int dfn[MAXN], low[MAXN], inx;
int stk[MAXN], top;
int vis[MAXN];
int scc, col[MAXN];
void tarjan(int u)
{
dfn[u] = low[u] = ++inx;
stk[++top] = u;
vis[u] = 1;
for (int v : g[u])
{
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u])
{
scc++;
int t;
do {
t = stk[top--];
vis[t] = 0;
for (int x : pos[t]) col[x] = scc;
} while (t != u);
}
}
void work(int K) //第K个按钮
{
//重置e1数组
for (int i = 1; i <= n; i++) in[i] = 0;
for (int i = 1; i <= n; i++) in[t[K][i]]++;
for (int i = 1; i <= n; i++)
if (in[i] >= 3) return; //入度>=3不符合条件
int sum2 = 0, p = 0; //入度为2的节点个数
for (int i = 1; i <= n; i++)
if (in[i] == 2) sum2++, p = i;
if (sum2 >= 2) return;
for (int i = 1; i <= cnt2; i++) e1[i] = e2[i];
cnt1 = cnt2;
cnt2 = 0;
if (sum2 == 1)
{
int x1 = 0, x2 = 0, y;
for (int i = 1; i <= n; i++)
if (t[K][i] == p) x1 = i;
for (int i = 1; i <= n; i++)
if (t[K][i] == p && i != x1) x2 = i;
for (int i = 1; i <= n; i++)
if (in[i] == 0) y = i;
e1[++cnt1] = (Edge){x1, y};
e1[++cnt1] = (Edge){x2, y};
}
else
{
for (int i = 1; i <= n; i++)
{
int x = i, y = t[K][i];
e1[++cnt1] = (Edge){x, y};
}
}
int last_scc = scc;
for (int i = 1; i <= last_scc; i++) g[i].clear();
for (int i = 1; i <= cnt1; i++)
{
int x = e1[i].x, y = e1[i].y;
if (col[x] != col[y])
{
g[col[x]].push_back(col[y]);
}
}
//tarjan清空
for (int i = 1; i <= last_scc; i++)
{
dfn[i] = low[i] = 0;
vis[i] = 0;
col[i] = 0;
}
inx = top = scc = 0;
for (int i = 1; i <= last_scc; i++)
if (!dfn[i]) tarjan(i);
//更新pos数组
for (int i = 1; i <= last_scc; i++) pos[i].clear();
for (int i = 1; i <= n; i++) pos[col[i]].push_back(i);
//更新g数组为topsort数组
for (int i = 1; i <= last_scc; i++) g[i].clear();
map<pair<int, int>, int> ma;
for (int i = 1; i <= cnt1; i++)
{
int x = e1[i].x, y = e1[i].y;
if (col[x] != col[y])
{
if (ma[make_pair(col[x], col[y])] == 1) continue;
g[col[y]].push_back(col[x]);
ma[make_pair(col[x], col[y])] = 1;
e2[++cnt2] = (Edge){x, y};
}
}
for (int i = 1; i <= scc; i++) in[i] = 0; //in数组清空
for (int i = 1; i <= scc; i++) f[i].reset();
for (int u = 1; u <= scc; u++)
for (int v : g[u]) in[v]++;
queue<int> q;
for (int i = 1; i <= scc; i++)
{
f[i].set(i);
if (in[i] == 0) q.push(i);
}
while (q.size())
{
int u = q.front();
q.pop();
for (int v : g[u])
{
f[v] |= f[u];
in[v]--;
if (in[v] == 0) q.push(v);
}
}
}
void solve()
{
n = read(), m = read(), q = read();
for (int i = 1; i <= m; i++)
{
scanf("%s", s + 1);
int len = strlen(s + 1);
for (int j = 1; j <= len; j += 2)
{
int x = s[j] - 48, y = s[j + 1] - 48;
t[i][(j + 1) / 2] = x * 50 + y;
}
}
for (int i = 1; i <= q; i++)
{
que[i].id = i;
scanf("%s", s + 1);
int x, y;
x = s[1] - 48, y = s[2] - 48;
que[i].a = x * 50 + y;
x = s[3] - 48, y = s[4] - 48;
que[i].b = x * 50 + y;
x = s[5] - 48, y = s[6] - 48;
que[i].c = x * 50 + y;
}
sort(que + 1, que + q + 1, [](Que A, Que B) {
return A.c < B.c;
});
scc = n;
for (int i = 1; i <= n; i++) pos[i].clear();
for (int i = 1; i <= n; i++)
{
pos[i].push_back(i);
col[i] = i;
f[i].reset(); //记得重置f数组!!!
f[i].set(i);
}
cnt1 = cnt2 = 0;
int j = 1;
for (int i = 1; i <= q; i++)
{
while (j <= que[i].c) work(j), j++;
int a = que[i].a, b = que[i].b;
que[i].ans = f[col[a]][col[b]];
}
sort(que + 1, que + q + 1, [](Que A, Que B) {
return A.id < B.id;
});
for (int i = 1; i <= q; i++) cout << que[i].ans;
cout << "\n";
}
int main()
{
int tt = read();
while (tt--) solve();
return 0;
}