#include<bits/stdc++.h>
using namespace std;

const int maxb=20;
const int maxs=1<<maxb;
int n,q,tot,top,rt;
int st[maxs<<1],ls[maxs<<1],rs[maxs<<1],tag0[maxs<<1],tag1[maxs<<1],tagx[maxs<<1],sdep[maxs<<1],cnt[maxs<<1];
vector<pair<pair<int,int>,int> >todo;

void apply0(int cur,int mask){
	tag1[cur]&=~mask;
	tagx[cur]&=~mask;
	tag0[cur]|=mask;
}
void apply1(int cur,int mask){
	tag0[cur]&=~mask;
	tagx[cur]&=~mask;
	tag1[cur]|=mask;
}
void applyx(int cur,int mask){
	int tmp=(tag0[cur]^tag1[cur])&mask;
	tag0[cur]^=tmp;
	tag1[cur]^=tmp;
	tagx[cur]^=mask&~tag0[cur]&~tag1[cur];
}

int newnode(int _cnt){
	int cur=top?st[--top]:tot++;
	ls[cur]=rs[cur]=-1;
	tag0[cur]=tag1[cur]=tagx[cur]=sdep[cur]=0;
	cnt[cur]=_cnt;
	return cur;
}

void merge(int &cur,int cur1,int cur2,int dep,int l,int r);
void pushdown(int cur,int dep,int l,int r){
	int mid=l+r>>1;
	if((tag0[cur]>>dep)&1){
		merge(ls[cur],ls[cur],rs[cur],dep-1,l,mid);
		rs[cur]=-1;
	}
	else if((tag1[cur]>>dep)&1){
		merge(rs[cur],ls[cur],rs[cur],dep-1,mid+1,r);
		ls[cur]=-1;
	}
	else if((tagx[cur]>>dep)&1)
		swap(ls[cur],rs[cur]);
	if(ls[cur]>=0)
		apply0(ls[cur],tag0[cur]),apply1(ls[cur],tag1[cur]),applyx(ls[cur],tagx[cur]);
	if(rs[cur]>=0)
		apply0(rs[cur],tag0[cur]),apply1(rs[cur],tag1[cur]),applyx(rs[cur],tagx[cur]);
	tag0[cur]=tag1[cur]=tagx[cur]=0;
}
void pushup(int cur,int dep){
	cnt[cur]=(ls[cur]>=0?cnt[ls[cur]]:0)+(rs[cur]>=0?cnt[rs[cur]]:0);
	sdep[cur]=(ls[cur]>=0?sdep[ls[cur]]:0)|(rs[cur]>=0?sdep[rs[cur]]:0);
	if(ls[cur]>=0&&rs[cur]>=0)sdep[cur]|=1<<dep;
}
void check(int cur,int dep,int l,int r){
	if(dep<0)return;
	if(sdep[cur]&(tag0[cur]|tag1[cur])){
		pushdown(cur,dep,l,r);
		int mid=l+r>>1;
		check(ls[cur],dep-1,l,mid);
		check(rs[cur],dep-1,mid+1,r);
		pushup(cur,dep);
	}
}
void merge(int &cur,int cur1,int cur2,int dep,int l,int r){
	if(cur1<0)cur=cur2;
	else if(cur2<0)cur=cur1;
	else{
		cur=cur1;
		if(dep>=0){
			pushdown(cur1,dep,l,r);
			pushdown(cur2,dep,l,r);
			int mid=l+r>>1;
			merge(ls[cur],ls[cur1],ls[cur2],dep-1,l,mid);
			merge(rs[cur],rs[cur1],rs[cur2],dep-1,mid+1,r);
			pushup(cur,dep);
		}
		st[top++]=cur2;
	}
}
void insert(int &cur,int dep,int edep,int l,int r,int k,int val){
	if(dep==edep){
		merge(cur,cur,val,dep,l,r);
		return;
	}
	if(cur<0)cur=newnode(0);
	pushdown(cur,dep,l,r);
	int mid=l+r>>1;
	if(k<=mid)insert(ls[cur],dep-1,edep,l,mid,k,val);
	else insert(rs[cur],dep-1,edep,mid+1,r,k,val);
	pushup(cur,dep);
}
void update(int &cur,int dep,int l,int r,int vl,int vr,int op,int mask){
	if(cur<0)return;
	if(l>=vl&&r<=vr){
		if(op==0){
			apply0(cur,mask);
			todo.push_back(make_pair(make_pair(l&((maxs-1)^mask),cur),dep));
		}
		else if(op==1){
			apply1(cur,mask);
			todo.push_back(make_pair(make_pair(l|mask,cur),dep));
		}
		else{
			applyx(cur,mask);
			todo.push_back(make_pair(make_pair(l^mask,cur),dep));
		}
		check(cur,dep,l,r);
		cur=-1;
		return;
	}
	pushdown(cur,dep,l,r);
	int mid=l+r>>1;
	if(mid>=vl)update(ls[cur],dep-1,l,mid,vl,vr,op,mask);
	if(mid<vr)update(rs[cur],dep-1,mid+1,r,vl,vr,op,mask);
	pushup(cur,dep);
}
int query(int cur,int dep,int l,int r,int vl,int vr){
	if(cur<0)return 0;
	if(l>=vl&&r<=vr)return cnt[cur];
	pushdown(cur,dep,l,r);
	int mid=l+r>>1;
	int sl=mid>=vl?query(ls[cur],dep-1,l,mid,vl,vr):0;
	int sr=mid<vr?query(rs[cur],dep-1,mid+1,r,vl,vr):0;
	return sl+sr;
}

int main(){
	rt=-1;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		insert(rt,maxb-1,-1,0,maxs-1,x,newnode(1));
	}
	while(q--){
		int op,l,r;
		scanf("%d%d%d",&op,&l,&r);
		op--;
		if(op<=2){
			int mask;
			scanf("%d",&mask);
			todo.clear();
			update(rt,maxb-1,0,maxs-1,l,r,op,op==0?(maxs-1)^mask:mask);
			for(int i=0;i<int(todo.size());i++)
				insert(rt,maxb-1,todo[i].second,0,maxs-1,todo[i].first.first,todo[i].first.second);
		}
		else
			printf("%d\n",query(rt,maxb-1,0,maxs-1,l,r));
	}
	return 0;
}
