#include <string>
#include <iostream>
#include <stack>
#include <queue> // priority_queue も入ってる
#include <set>   // 要素数は size() で取得 multisetもある
#include <map>
#include <array> // sizeはコンパイル時定数で固定
#include <vector>
#include <numeric>   // accumulate, gcd
#include <algorithm> // count_ifに必要
#include <iomanip>   // cout << setprecision(15) << x で小数の出力精度を指定
#include <tuple>
#include <utility> //pair
#include <cmath>
#include <random>

using namespace std;
using ll = long long;

#define rep(i, n) for (int i = 0; i < (n); ++i)

// BIT
// Binary Indexed Tree
// Fenwick Tree

// Inverse Semigroup で使えますが、普通は群でしょう。
// 可逆でなく、単なるモノイドの場合はセグメントツリーを使うこと。

// 0番は空けて、1-indexedです。

// 3 1 4 1 5 9 2 6 5 3 5を1回更新して1回区間和を出す例題になってます。

// 更新メソッド
// incrementは増分。新しい値そのものではないので注意！
int updateTree(vector<ll> &tree, int index, ll increment)
{
    while (index < tree.size())
    {
        tree[index] = tree[index] ^ increment;
        // 1110 = 1110 + 0010 → 10000 みたいな。一番下位の1を足す。
        index += (index & (-index));
    }
    return 0;
}

// 累積和取得メソッド。区間和の取得はこれの差で。
ll getSum(vector<ll> &tree, int index)
{
    ll result = 0;
    while (index > 0)
    {
        result = result ^ tree[index];
        index -= (index & (-index));
    }
    return result;
}

int main()
{
    // TODO: 入力を受け取る。
    ll n, q;
    cin >> n >> q;
    vector<ll> a(n);
    rep(i, n) cin >> a[i];
    vector<ll> T(q), X(q), Y(q);
    rep(i, q) cin >> T[i] >> X[i] >> Y[i];

    // 構築。
    vector<ll> tree(n + 1, 0);
    for (int i = 1; i <= n; ++i)
    {
        updateTree(tree, i, a[i - 1]);
    }

    // TODO: クエリの処理
    rep(i, q)
    {
        // 0 <= i <= q-1
        if (T[i] == 1)
        {
            // update
            updateTree(tree, X[i], Y[i]);
        }
        else
        {
            // output
            ll result = getSum(tree, Y[i]) ^ getSum(tree, X[i] - 1);
            cout << result << endl;
        }
    }

    return 0;
}
#include <bits/stdc++.h>
#define isz(x) (int)(x).size()
struct Fenwick {
    std::vector<int> data;
    Fenwick(int n) : data(n,0) { }
    void inc(int p, int x) {
        for (int i = p; i < isz(data); i |= i+1)
            data[i] += x;
    }
    void inverse(int i) {
        int oldValue = get(i,i);
        int newValue = 1-oldValue;
        inc(i,newValue-oldValue);
    }
    int get(int r) {
        int res(0);
        while (r >= 0) {
            res += data[r];
            r = (r & (r+1)) - 1;
        }
        return res;
    }
    int get(int l, int r) {
        return get(r) - get(l-1);
    }
};
int main() {
    int n,q;
    scanf("%d %d", &n, &q);
    std::vector<Fenwick> fenw(30,Fenwick(1+n));
    for (int i = 1, a; i <= n; i++) {
        scanf("%d", &a);
        for (int bit = 0; bit < 30; bit++)
            if((a >> bit)&1)fenw[bit].inverse(i);
    }
    while (q --> 0) {
        int t,x,y; scanf("%d %d %d", &t, &x, &y);
        if (t == 1) {
            for (int bit = 0; bit < 30; bit++)
                if ((y >> bit) & 1) fenw[bit].inverse(x);
        } else {
            int answ{0};
            for (int bit = 0; bit < 30; bit++)
                answ |= (fenw[bit].get(x,y)&1) << bit;
            printf("%d\n", answ);
        }
    }
}