#include <bits/stdc++.h>   using namespace std;   using ll = long long;      int MOD;   struct modint {      private:          int v;          static int minv(int a, int m) {           a %= m;           assert(a);           return a == 1 ? 1 : int(m - ll(minv(m, a)) * ll(m) / a);       }      public:          modint() : v(0) {}       modint(ll v_) : v(int(v_ % MOD)) { if (v < 0) v += MOD; }       explicit operator int() const { return v; }       friend std::ostream& operator << (std::ostream& out, const modint& n) { return out << int(n); }       friend std::istream& operator >> (std::istream& in, modint& n) { ll v_; in >> v_; n = modint(v_); return in; }          friend bool operator == (const modint& a, const modint& b) { return a.v == b.v; }       friend bool operator != (const modint& a, const modint& b) { return a.v != b.v; }          modint inv() const {           modint res;           res.v = minv(v, MOD);           return res;       }       friend modint inv(const modint& m) { return m.inv(); }       modint neg() const {           modint res;           res.v = v ? MOD-v : 0;           return res;       }       friend modint neg(const modint& m) { return m.neg(); }          modint operator- () const {           return neg();       }       modint operator+ () const {           return modint(*this);       }          modint& operator ++ () {           v ++;           if (v == MOD) v = 0;           return *this;       }       modint& operator -- () {           if (v == 0) v = MOD;           v --;           return *this;       }       modint& operator += (const modint& o) {           v += o.v;           if (v >= MOD) v -= MOD;           return *this;       }       modint& operator -= (const modint& o) {           v -= o.v;           if (v < 0) v += MOD;           return *this;       }       modint& operator *= (const modint& o) {           v = int(ll(v) * ll(o.v) % MOD);           return *this;       }       modint& operator /= (const modint& o) {           return *this *= o.inv();       }          friend modint operator ++ (modint& a, int) { modint r = a; ++a; return r; }       friend modint operator -- (modint& a, int) { modint r = a; --a; return r; }       friend modint operator + (const modint& a, const modint& b) { return modint(a) += b; }       friend modint operator - (const modint& a, const modint& b) { return modint(a) -= b; }       friend modint operator * (const modint& a, const modint& b) { return modint(a) *= b; }       friend modint operator / (const modint& a, const modint& b) { return modint(a) /= b; }   };   namespace IO {       template<class T>       void _R(T &x) { cin >> x; }       void _R(int &x) { scanf( %d , &x); }       void _R(ll &x) { scanf( %lld , &x); }       void _R(double &x) { scanf( %lf , &x); }       void _R(char &x) { x = getchar(); }       void _R(char *x) { scanf( %s , x); }       void R() {}       template<class T, class... U>       void R(T &head, U &... tail) { _R(head), R(tail...); }       template<class T>       void _W(const T &x) { cout << x; }       void _W(const int &x) { printf( %d , x); }       void _W(const ll &x) { printf( %lld , x); }       void _W(const double &x) { printf( %.16f , x); }       void _W(const char &x) { putchar(x); }       void _W(const char *x) { printf( %s , x); }       template<class T, class U>       void _W(const pair<T, U> &x) { _W(x.first), putchar(   ), _W(x.second); }       template<class T>       void _W(const vector<T> &x) { for (auto i = x.begin(); i != x.end(); _W(*i++)) if (i != x.cbegin()) putchar(   ); }       void W() {}       template<class T, class... U>       void W(const T &head, const U &... tail) { _W(head), putchar(sizeof...(tail) ?     :   n ), W(tail...); }   }   using namespace IO;   template <typename T> T pow(T a, long long b) {       assert(b >= 0);       T r = 1; while (b) { if (b & 1) r *= a; b >>= 1; a *= a; } return r;   }      const int maxn = 2e5+50;   const int maxp = maxn*32+5;   const int K = 20;   const int M = 1 << K;   int ls[maxp], rs[maxp], tot;   // 0, 1, cnt, XOR   int t0[maxp], t1[maxp], p[maxp], txor[maxp];      inline void pushup(int x) {       p[x] = p[ls[x]] + p[rs[x]];       t0[x] = t0[ls[x]] | t0[rs[x]];       t1[x] = t1[ls[x]] | t1[rs[x]];   }   inline void XOR(int x, int t, int dep = K) {       if (!x) return;       txor[x] ^= t;       if (t >> (dep - 1) & 1) swap(ls[x], rs[x]);       int a = (t0[x] & (~t)) | (t1[x] & t), b = (t1[x] & (~t)) | (t0[x] & t);       t0[x] = a, t1[x] = b;   }   inline void pushdown(int x, int dep) {       if (txor[x]) {           XOR(ls[x], txor[x], dep - 1), XOR(rs[x], txor[x], dep - 1);           txor[x] = 0;       }   }   inline void insert(int &x, int s, int dep = K) {       if (!x) x = ++tot;       if (!dep) {           t1[x] = s, t0[x] = s ^ (M - 1);           p[x] = 1;           return;       }       insert((s >> (dep - 1) & 1) ? rs[x] : ls[x], s, dep - 1);       pushup(x);   }   inline void split(int &x, int &y, int l, int r, int le, int re, int dep = K) {       if (le <= l && r <= re) {           y = x; x = 0;           return;       }       int mid = l + r >> 1; pushdown(x, dep);       y = ++tot;       if (le <= mid) split(ls[x], ls[y], l, mid, le, re, dep - 1);       if (re > mid) split(rs[x], rs[y], mid + 1, r, le, re, dep - 1);       pushup(x), pushup(y);   }   inline void merge(int &x, int y, int dep = K) {       if (!x || !y) {           x = x + y;           return;       }       if (!dep) return;       pushdown(x, dep), pushdown(y, dep);       merge(ls[x], ls[y], dep - 1), merge(rs[x], rs[y], dep - 1);       pushup(x);   }   inline void OR(int x, int s, int dep = K) {       if (!x) return;       if (!(s & t0[x] & t1[x])) {           XOR(x, s & t0[x], dep);           return;       }       pushdown(x, dep);       if (s >> (dep - 1) & 1) {           XOR(ls[x], 1 << (dep - 1), dep - 1);           merge(rs[x], ls[x], dep - 1);           ls[x] = 0;       }       OR(ls[x], s, dep - 1), OR(rs[x], s, dep - 1);       pushup(x);   }      int main() {       int n, q, x = 0;       R(n, q);       for (int i = 1; i <= n; ++i) {           int v; R(v); insert(x, v);       }       for (; q; --q) {           int oth;           int t, l, r, v; R(t, l, r);           split(x, oth, 0, M - 1, l, r);           if (t == 1) R(v),XOR(oth, M - 1),OR(oth, v ^ (M - 1)),XOR(oth, M - 1);           else if (t == 2) R(v),OR(oth, v);           else if (t == 3) R(v), XOR(oth, v);           else W(p[oth]);           merge(x, oth);       }       return 0;   }