#include <bits/stdc++.h>
#define f(a, n) for (int a = 0; a < n; a++)
#define F(a, n) for (int a = 1; a <= n; a++)
 
using namespace std;

/*
We declare an array of size 2^20. We will pretend N = 2^19. (sort of)
The i-th element is stored in A[N+i]. (0 indexed)
for i in [1, N-1], A[i] = A[2i] + A[2i+1].
When we update element i, let j = i + N, then we update A[j], A[j/2], A[j/4],...
When we query for the sum of [1, i], if the last bit is 1, we add A[j]. Either way, we set j = j / 2. Proceed until j == 0.
*/

int A[1<<20];
constexpr int N = 1 << 19;

int sumto(int i){ // sums to i - 1 inclusive
	int ret = 0;
	int j = i + N;
	while (i > 0){
		if (i & 1) ret ^= A[j - 1];
		i >>= 1;
		j >>= 1;
	}
	//i = 6 = 110, we want [0, 3] + [4, 5] = A[2] + A[6]
	//i = 7 = 111, we want A[2]+A[6]+A[14]
	//i = 5 = 101, we want A[2]+A[12]
	return ret;
}

int main(){
	int n, q;
	cin >> n >> q;
	f(i, n){
		cin>>A[i + N];
	}
	for (int i = N - 1; i > 0; i--){
		A[i] = A[2*i] ^ A[2*i+1];
	}
	f(i, q){
		int x, y, z;
		cin>>x>>y>>z;
		if (x == 1){
			int j = y-1 + N;
			while (j > 0){
				A[j] ^= z;
				j >>= 1;
			}
		}else{
			//cout<<sumto(z)<<" "<<sumto(y-1)<<"!"<<endl;
			cout << (sumto(z) ^ sumto(y-1)) << endl;
		}
	}
}
#include<bits/stdc++.h> 
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace std;
using namespace __gnu_pbds;  
#define ordered_set tree<ll, null_type , less<ll> , rb_tree_tag , tree_order_statistics_Node_update> 
#define ll long long
#define ull unsigned long long
#define pb push_back
#define inf 3e18
#define mk make_pair
#define ld long double
#define mod 1000000007 
#define fi first
#define se second
#define fastIO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define test ll t; cin>>t; while(t--)
#define setbits __builtin_popcount
#define endl '\n'
#define LOCAL
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifdef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i));}
sim, class b dor(pair < b, c > d) {
    ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
    *this << "[";
    for (auto it = d.b; it != d.e; ++it)
        *this << ", " + 2 * (it == d.b) << *it;
    ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
#define maxn 300001
vector<ll>a(maxn);
ll seg[4*maxn];
void build(ll v,ll l,ll r)
{
	if(l==r)
	{
		seg[v]=a[l];
		return;
	}
	ll mid=(l+r)/2;
	build(2*v,l,mid);
	build(2*v+1,mid+1,r);
	seg[v]=seg[2*v]^seg[2*v+1];
}
void update(ll v,ll l,ll r,ll pos,ll val)
{
	if(l==r)
	{
		seg[v]^=val;
		return;
	}
	ll mid=(l+r)/2;
	if(pos<=mid)
	{
		update(2*v,l,mid,pos,val);
	}
	else
	{
		update(2*v+1,mid+1,r,pos,val);
	}
	seg[v]=seg[2*v]^seg[2*v+1];
}
ll query(ll v,ll l,ll r,ll x,ll y)
{
	if(y<x)
	{
		return 0;
	}
	if(x<=l && r<=y)
	{
		return seg[v];
	}	
	ll mid=(l+r)/2,val,val1;
	val=query(2*v,l,mid,x,min(y,mid));
	val1=query(2*v+1,mid+1,r,max(mid+1,x),y);
	return val^val1;
}
int main()
{
	fastIO;
	ll n,q;
	cin>>n>>q;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	build(1,0,n-1);
	ll x,y,z,val;
	while(q--)
	{
		cin>>x>>y>>z;
		if(x==1)
		{
			y--;
			update(1,0,n-1,y,z);
		}
		else
		{
			y--;
			z--;
			val=query(1,0,n-1,y,z);
			cout<<val<<endl;
		}
	}
}