#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;
template<class T>
bool chmax(T &a, const T &b){
if(a < b){ a = b; return true; }
return false;
}
template<class T>
bool chmin(T &a, const T &b){
if(a > b){ a = b; return true; }
return false;
}
constexpr int inf = 2e9, L = 256;
struct node {
int l, r, v;
inline node() {}
inline node(int _l, int _r, int _v) : l(_l), r(_r), v(_v) {}
inline int size() { return r - l + 1; }
inline void apply(int tmin, int tmax) {
if (v < tmin) v = tmin;
if (v > tmax) v = tmax;
}
inline pair<node, node> split(int p) {
return {node(l, p - 1, v), node(p, r, v)};
}
inline int query(int _v) { return (v < _v ? size() : 0); }
};
struct block {
int len, tmin, tmax;
vector<int> pre;
vector<node> seg, sorted, tmp;
array<int, L> cnt;
inline block() {}
inline void build() {
len = seg.size(), tmin = 0, tmax = inf;
sorted = seg, sort();
pre.resize(len + 1), pre[0] = 0;
for (int i = 0; i < len; i++) pre[i + 1] = pre[i] + sorted[i].size();
}
inline void init(int n) {
len = 1, tmin = 0, tmax = inf;
seg = {node(0, n - 1, 0)};
sorted = {node(0, n - 1, 0)};
pre.resize(2);
pre[0] = 0, pre[1] = n;
}
inline int bl() { return seg[0].l; }
inline int br() { return seg[len - 1].r; }
inline int size() { return br() - bl() + 1; }
inline void sort() {
tmp.resize(len);
for (int i = 0; i < L; i++) cnt[i] = 0;
for (int i = 0; i < len; i++) cnt[sorted[i].v & 0xff]++;
for (int i = 1; i < L; i++) cnt[i] += cnt[i - 1];
for (int i = len - 1; i >= 0; i--) tmp[--cnt[sorted[i].v & 0xff]] = sorted[i];
for (int i = 0; i < L; i++) cnt[i] = 0;
for (int i = 0; i < len; i++) cnt[(tmp[i].v >> 8) & 0xff]++;
for (int i = 1; i < L; i++) cnt[i] += cnt[i - 1];
for (int i = len - 1; i >= 0; i--) sorted[--cnt[(tmp[i].v >> 8) & 0xff]] = tmp[i];
for (int i = 0; i < L; i++) cnt[i] = 0;
for (int i = 0; i < len; i++) cnt[(sorted[i].v >> 16) & 0xff]++;
for (int i = 1; i < L; i++) cnt[i] += cnt[i - 1];
for (int i = len - 1; i >= 0; i--) tmp[--cnt[(sorted[i].v >> 16) & 0xff]] = sorted[i];
for (int i = 0; i < L; i++) cnt[i] = 0;
for (int i = 0; i < len; i++) cnt[(tmp[i].v >> 24) & 0xff]++;
for (int i = 1; i < L; i++) cnt[i] += cnt[i - 1];
for (int i = len - 1; i >= 0; i--) sorted[--cnt[(tmp[i].v >> 24) & 0xff]] = tmp[i];
}
inline void pushdown() {
for (int i = 0; i < len; i++) {
seg[i].apply(tmin, tmax);
sorted[i].apply(tmin, tmax);
}
tmin = 0, tmax = inf;
}
inline int belong(int x) {
for (int i = 0; i < len; i++)
if (seg[i].l <= x && x <= seg[i].r) return i;
return -1;
}
inline int query(int v) {
if (v > tmax) return size();
if (v <= tmin) return 0;
int l = 0, r = len;
while (l ^ r) {
const int mid = (l + r) >> 1;
if (sorted[mid].v < v) l = mid + 1;
else r = mid;
}
return pre[l];
}
inline int query(int l, int r, int v) {
int bl = belong(l), br = belong(r), res = 0;
pushdown();
if (bl == br) return (seg[bl].v < v ? r - l + 1 : 0);
res += seg[bl].split(l).second.query(v);
for (int i = bl + 1; i < br; i++) res += seg[i].query(v);
res += seg[br].split(r + 1).first.query(v);
return res;
}
inline void update(int t1, int t2) {
if (t1 > tmin) {
tmin = t1;
if (t1 > tmax) tmax = t1;
}
if (t2 < tmax) {
tmax = t2;
if (t2 < tmin) tmin = t2;
}
}
inline bool update(int l, int r, int t1, int t2) {
int bl = belong(l), br = belong(r);
pushdown();
if (bl == br) {
tmp.clear();
for (int i = 0; i < bl; i++) tmp.push_back(seg[i]);
auto [lef, rem] = seg[bl].split(l);
if (lef.size() > 0) tmp.push_back(lef);
if (rem.size() > 0) {
auto [mid, rig] = rem.split(r + 1);
if (mid.size() > 0) {
mid.apply(t1, t2);
tmp.push_back(mid);
}
if (rig.size() > 0) tmp.push_back(rig);
}
for (int i = bl + 1; i < len; i++) tmp.push_back(seg[i]);
seg = tmp;
return seg.size() >= L;
}
tmp.clear();
for (int i = 0; i < bl; i++) tmp.push_back(seg[i]);
auto [nl, nr] = seg[bl].split(l);
if (nl.size() > 0) tmp.push_back(nl);
if (nr.size() > 0) {
nr.apply(t1, t2);
tmp.push_back(nr);
}
for (int i = bl + 1; i < br; i++) {
node cur = seg[i];
cur.apply(t1, t2);
tmp.push_back(cur);
}
auto [ml, mr] = seg[br].split(r + 1);
if (ml.size() > 0) {
ml.apply(t1, t2);
tmp.push_back(ml);
}
if (mr.size() > 0) tmp.push_back(mr);
for (int i = br + 1; i < len; i++) tmp.push_back(seg[i]);
seg = tmp;
return seg.size() >= L;
}
};
struct DS {
int n;
list<block> rec;
using iter = list<block>::iterator;
inline DS() {}
inline DS(int _n) : n(_n) {
block tmp; tmp.init(n);
rec.push_back(tmp);
}
inline iter belong(int x) {
for (iter it = rec.begin(); it != rec.end(); it++)
if (it->bl() <= x && x <= it->br()) return it;
return rec.end();
}
inline void refact(iter b) {
int half = b->len / 2;
block tmp;
tmp.seg.resize(b->len - half);
for (int i = half; i < b->len; i++) tmp.seg[i - half] = b->seg[i];
b->seg.resize(half);
b->build(), tmp.build();
rec.insert(next(b), tmp);
}
inline int query(int l, int r, int v) {
iter bl = belong(l), br = belong(r);
if (bl == br) return bl->query(l, r, v);
int res = bl->query(l, bl->br(), v) + br->query(br->bl(), r, v);
for (auto it = next(bl); it != br; it++) res += it->query(v);
return res;
}
inline void _update(iter b, int l, int r, int t1, int t2) {
if (b->update(l, r, t1, t2)) refact(b);
else b->build();
}
inline void update(int l, int r, int t1, int t2) {
iter bl = belong(l), br = belong(r);
if (bl == br) return _update(bl, l, r, t1, t2);
_update(bl, l, bl->br(), t1, t2);
_update(br, br->bl(), r, t1, t2);
for (auto it = next(bl); it != br; it++) it->update(t1, t2);
}
};
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, q, c;
cin >> n >> q >> c;
DS ds(n);
for (int i = 0, op, l, r, h, lst = 0; i < q; i++) {
cin >> op >> l >> r >> h;
l ^= lst, r ^= lst, h ^= lst;
l--, r--;
if (l > r) continue;
if (op == 1) {
cout << (lst = ds.query(l, r, h)) << endl;
lst *= c;
}
if (op == 2) ds.update(l, r, 0, h);
if (op == 3) ds.update(l, r, h, inf);
}
return 0;
}