#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int SZ = 65;
struct mat {
bitset<SZ> a[SZ];
};
mat transpose(mat A) {
mat B;
for (int i = 0; i < SZ; i++) {
for (int j = 0; j < SZ; j++) {
B.a[i][j] = A.a[j][i];
}
}
return B;
}
mat mult(mat A, mat B) {
B = transpose(B);
mat R;
for (int i = 0; i < SZ; i++) {
for (int j = 0; j < SZ; j++) {
R.a[i][j] = (A.a[i] & B.a[j]).count() & 1;
}
}
return R;
}
bitset<SZ> mult(mat A, bitset<SZ> x) {
bitset<SZ> y;
for (int i = 0; i < SZ; i++) {
y[i] = (A.a[i] & x).count() & 1;
}
return y;
}
const int MAXN = 20202;
struct seg {
mat tree[4 * MAXN];
void update(int a, mat &A, int l, int r, int x) {
if (l == r) {
tree[x] = A;
return;
}
int m = (l + r) / 2;
if (a <= m) {
update(a, A, l, m, 2 * x);
}
else {
update(a, A, m + 1, r, 2 * x + 1);
}
tree[x] = mult(tree[2 * x + 1], tree[2 * x]);
}
void query(int a, int b, bitset<SZ> &v, int l, int r, int x) {
if (b < l || a > r) return;
if (a <= l && r <= b) {
v = mult(tree[x], v);
return;
}
int m = (l + r) / 2;
query(a, b, v, l, m, 2 * x);
query(a, b, v, m + 1, r, 2 * x + 1);
}
} t1;
mat f() {
int m; cin >> m;
mat A;
A.a[SZ - 1][SZ - 1] = 1;
for (int j = 0; j < m; j++) {
ull s, o, a;
cin >> s >> o >> a;
for (int k = 0; k < SZ - 1; k++) {
int b = (a >> k & 1);
if (o == 0 && b == 1) {
A.a[k][SZ - 1].flip();
}
else if (o == b) {
A.a[k][(k + SZ - 1 - s) % (SZ - 1)].flip();
}
}
}
ull b; cin >> b;
for (int k = 0; k < SZ - 1; k++) {
if (b >> k & 1) {
A.a[k][SZ - 1].flip();
}
}
return A;
}
int main() {
cin.tie(0); ios_base::sync_with_stdio(0);
int n, q, c;
cin >> n >> q >> c;
for (int i = 0; i < n; i++) {
t1.update(i, f(), 0, n - 1, 1);
}
while (q--) {
int op; cin >> op;
if (op == 0) {
int s, e; ull x;
cin >> s >> e >> x;
bitset<SZ> v;
for (int i = 0; i < SZ - 1; i++) {
v[i] = (x >> i & 1);
}
v[SZ - 1] = 1;
t1.query(s - 1, e - 1, v, 0, n - 1, 1);
ull ans = 0;
for (int i = 0; i < SZ - 1; i++) {
ans ^= (ull)v[i] << i;
}
cout << ans << '\n';
}
else {
int x; cin >> x;
t1.update(x - 1, f(), 0, n - 1, 1);
}
}
}