#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;
}