#include<bits/stdc++.h>
#define int long long
#define mid ((l + r) >> 1)
#define lchild (root << 1)
#define rchild ((root << 1) + 1)
using namespace std;
const int N = 1e5 + 9,LOGV = 30;
int n,m,root;
int a[N],logn = 25;
struct Trie{
struct node{
int ch[2];
int cnt;
} t[N * LOGV];
int Root[N],node_cnt;
int new_node(){
return ++node_cnt;
}
void insert(int last_u,int u,int x){
for(int i = logn;i >= 0;i--){
t[u].cnt = t[last_u].cnt + 1;
int c = (x >> i) & 1;
if(!t[u].ch[c])
t[u].ch[c] = new_node();
t[u].ch[c ^ 1] = t[last_u].ch[c ^ 1];
u = t[u].ch[c];
last_u = t[last_u].ch[c];
}
t[u].cnt = t[last_u].cnt + 1;
}
int query(int last_u,int u,int x){
int ret = 0;
for(int i = logn;i >= 0;i--){
int c = (x >> i) & 1;
if(t[t[u].ch[c ^ 1]].cnt - t[t[last_u].ch[c ^ 1]].cnt){
u = t[u].ch[c ^ 1];
last_u = t[last_u].ch[c ^ 1];
ret = (ret << 1) | 1;
}
else{
u = t[u].ch[c];
last_u = t[last_u].ch[c];
ret <<= 1;
}
}
return ret;
}
} trie;
int s[N],len;
struct edge{
int to,nex;
} e[N << 1];
int head[N],ecnt;
void addedge(int u,int v){
ecnt++;
e[ecnt] = (edge){v,head[u]};
head[u] = ecnt;
}
int fa[N],siz[N],dep[N];
int w_ch[N];
void dfs1(int u,int father){
fa[u] = father;
siz[u] = 1;
dep[u] = dep[father] + 1;
for(int i = head[u];i;i = e[i].nex){
int v = e[i].to;
if(v != father){
dfs1(v,u);
siz[u] += siz[v];
if(siz[v] > siz[w_ch[u]])
w_ch[u] = v;
}
}
}
int top[N];
int dfn[N],rdfn[N],id;
void dfs2(int u,int link_top){
id++;
dfn[u] = id;
rdfn[id] = u;
top[u] = link_top;
len++;
s[len] = s[len - 1] ^ a[u];
trie.Root[id] = trie.new_node();
trie.insert(trie.Root[id - 1],trie.Root[id],s[len]);
if(w_ch[u]){
dfs2(w_ch[u],link_top);
for(int i = head[u];i;i = e[i].nex){
int v = e[i].to;
if(v != fa[u] && v != w_ch[u])
dfs2(v,v);
}
}
}
int query1(int root,int w){
return trie.query(trie.Root[dfn[root] - 1],trie.Root[dfn[root] + siz[root] - 1],w);
}
int query2(int u,int v,int w){
int l,r,ret = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])
swap(u,v);
l = dfn[top[u]],r = dfn[u];
ret = max(ret,trie.query(trie.Root[l - 1],trie.Root[r],w));
u = fa[top[u]];
}
if(dep[u] > dep[v])
swap(u,v);
l = dfn[u],r = dfn[v];
ret = max(ret,trie.query(trie.Root[l - 1],trie.Root[r],w));
return ret;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
root = 1;
for(int i = 1;i <= n;i++)
cin >> a[i];
for(int i = 1;i < n;i++){
int u,v;
cin >> u >> v;
addedge(u,v);
addedge(v,u);
}
trie.Root[0] = trie.new_node();
dfs1(root,0);
dfs2(root,root);
while(m--){
int op;
cin >> op;
if(op == 1){
int u,w;
cin >> u >> w;
cout << query1(u,w) << '\n';
}
else if(op == 2){
int u,v,w;
cin >> u >> v >> w;
cout << query2(u,v,w) << '\n';
}
}
return 0;
}