#include #include #include using namespace std; struct Point { int p, q, r, id; }; // CDQ分割用のBIT struct BIT { int n; vector tree; BIT(int n) : n(n), tree(n + 1, 0) {} void add(int i, int val) { for (; i <= n; i += i & -i) tree[i] += val; } int query(int i) { int sum = 0; for (; i > 0; i -= i & -i) sum += tree[i]; return sum; } void clear(int i) { for (; i <= n; i += i & -i) { if (tree[i] == 0) break; tree[i] = 0; } } }; int N; long long M; vector D; vector pts; BIT* bit; void cdq(int L, int R) { if (L >= R) return; int mid = L + (R - L) / 2; cdq(L, mid); cdq(mid + 1, R); int i = L, j = mid + 1; vector temp; temp.reserve(R - L + 1); while (i <= mid && j <= R) { if (pts[i].q > pts[j].q) { bit->add(pts[i].r, 1); temp.push_back(pts[i++]); } else { D[pts[j].id] += bit->query(N) - bit->query(pts[j].r); temp.push_back(pts[j++]); } } while (i <= mid) { bit->add(pts[i].r, 1); temp.push_back(pts[i++]); } while (j <= R) { D[pts[j].id] += bit->query(N) - bit->query(pts[j].r); temp.push_back(pts[j++]); } for (int k = L; k <= mid; k++) bit->clear(pts[k].r); for (int k = 0; k < temp.size(); k++) pts[L + k] = temp[k]; } void solve() { cin >> N >> M; vector P(N + 1), Q(N + 1), R(N + 1); vector posP(N + 1), posQ(N + 1), posR(N + 1); for (int i = 1; i <= N; i++) { cin >> P[i]; posP[P[i]] = i; } for (int i = 1; i <= N; i++) { cin >> Q[i]; posQ[Q[i]] = i; } for (int i = 1; i <= N; i++) { cin >> R[i]; posR[R[i]] = i; } pts.assign(N + 1, {0, 0, 0, 0}); for (int i = 1; i <= N; i++) { pts[i] = {posP[i], posQ[i], posR[i], i}; } sort(pts.begin() + 1, pts.end(), [](const Point& a, const Point& b) { return a.p > b.p; }); D.assign(N + 1, 0); bit = new BIT(N); cdq(1, N); delete bit; vector V0; long long ways = 1; for (int i = 1; i <= N; i++) { if (D[i] == 0) V0.push_back(i); else ways = (ways * D[i]) % M; } int n0 = V0.size(); if (n0 == 0) { cout << 0 << "\n"; return; } vector>> edges(n0, vector>(3)); for (int i = 0; i < n0; i++) { for (int j = 0; j < n0; j++) { if (i == j) continue; int u = V0[i], v = V0[j]; bool pq = (posP[u] < posP[v]); bool qq = (posQ[u] < posQ[v]); bool rq = (posR[u] < posR[v]); if (!pq && qq && rq) edges[i][0].push_back(j); if (pq && !qq && rq) edges[i][1].push_back(j); if (pq && qq && !rq) edges[i][2].push_back(j); } } int PN = P[N], QN = Q[N], RN = R[N]; int p_n = -1, q_n = -1, r_n = -1; for (int i = 0; i < n0; i++) { if (V0[i] == PN) p_n = i; if (V0[i] == QN) q_n = i; if (V0[i] == RN) r_n = i; } if (p_n == -1 || q_n == -1 || r_n == -1) { cout << 0 << "\n"; return; } int K = 0; vector out_node(n0, -1); vector out_color(n0, -1); auto check_tree = [&]() { int root = -1; for (int i = 0; i < n0; i++) { if (out_node[i] == -1) { if (root != -1) return false; root = i; } } if (root == -1) return false; vector vis(n0, false); int visited_count = 0; auto trace = [&](int start, int color) { int curr = start; while (curr != root) { if (vis[curr]) return false; vis[curr] = true; visited_count++; if (out_color[curr] != color) return false; curr = out_node[curr]; } return true; }; if (!trace(p_n, 0) || !trace(q_n, 1) || !trace(r_n, 2)) return false; if (!vis[root]) { vis[root] = true; visited_count++; } return visited_count == n0; }; auto dfs = [&](auto& self, int idx, bool has_root) -> void { if (idx == n0) { if (has_root && check_tree()) K++; return; } if (!has_root) { out_node[idx] = -1; out_color[idx] = -1; self(self, idx + 1, true); } for (int c = 0; c < 3; c++) { for (int v : edges[idx][c]) { out_node[idx] = v; out_color[idx] = c; self(self, idx + 1, has_root); } } }; dfs(dfs, 0, false); cout << (ways * K) % M << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int T; if (cin >> T) { while (T--) solve(); } return 0; }