#include <bits/stdc++.h>
// #include <iostream>
// #include <cstring>
// #include <string>
// #include <algorithm>
// #include <cmath>
// #include <cstdio>
// #include <queue>
// #include <stack>
// #include <map>
// #include <bitset>
// #include <set>
// #include <vector>
// #include <iomanip>
#define ll long long
#define ull unsigned long long
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define bep(i, a, b) for(int i = a; i >= b; --i)
#define lowbit(x) (x&(-x))
#define MID (l + r) / 2
#define ls pos*2
#define rs pos*2+1
#define ios() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int N = 3e5 + 1010;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
int fa[N], son[N][2], dp[N], tag[N];
int arr[N];
inline void pushup(int x) {
dp[x] = dp[son[x][0]] ^ dp[son[x][1]] ^ arr[x];
}
inline void pushr(int x) {
swap(son[x][0], son[x][1]);
tag[x] ^= 1;
}
inline void pushdown(int x) {
if(tag[x]) {
pushr(son[x][0]);
pushr(son[x][1]);
tag[x] = 0;
}
}
inline int nroot(int x) {
return son[fa[x]][0] == x || son[fa[x]][1] == x;
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int k = (son[y][1] == x);
int t = son[x][!k];
if(nroot(y)) son[z][son[z][1] == y] = x; // 与正常splay不一样,不能让这颗splay树的父亲认子,不然就变成了实边。
son[x][!k] = y;
son[y][k] = t;
if(t) fa[t] = y;
fa[y] = x;
fa[x] = z;
pushup(y);
}
inline void pushall(int x) {
if(nroot(x)) pushall(fa[x]);
pushdown(x);
}
inline void splay(int x) {
int y, z;
pushall(x);
while(nroot(x)) {
y = fa[x], z = fa[y];
if(nroot(y)) {
((son[z][1] == y) == (son[y][1] == x)) ? rotate(y) : rotate(x);
}
rotate(x);
}
pushup(x);
}
inline void access(int x) {
for(int y = 0; x; x = fa[y = x]) {
splay(x);
son[x][1] = y;
pushup(x);
}
}
inline void makeroot(int x) {
access(x);
splay(x);
pushr(x);
}
inline void split(int x, int y) {
makeroot(x);
access(y);
splay(y);
}
// 找该点所在数的根
inline int findroot(int x) {
access(x);
splay(x);
while(son[x][0]) {
pushdown(x);
x = son[x][0];
}
splay(x);
return x;
}
// 链接两点
inline void link(int x, int y) {
makeroot(x);
if(findroot(y) != x) fa[x] = y;
}
// 切断两点
inline void cut(int x, int y) {
makeroot(x);
if(findroot(y) == x && fa[y] == x && !son[y][0]) {
fa[y] = son[x][1] = 0;
pushup(x);
}
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%d", &arr[i]);
while(m--) {
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
switch(op) {
case 0: split(x, y); printf("%d\n", dp[y]); break;
case 1: link(x, y); break;
case 2: cut(x, y); break;
case 3: splay(x); arr[x] = y; break;
}
}
return 0;
}