#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,root,mod;
int val[maxn],cnt,size[maxn],son[maxn],top[maxn],dep[maxn],f[maxn],valt[200005],id[maxn];
struct node{
int val,l,r;
}a[maxn*4];
vector<int> G[maxn];
void pushup(int u){
a[u].val=a[u*2].val^a[u*2+1].val;
}
void add(int u,int k,int v){
int L=a[u].l,R=a[u].r,M=L+R>>1;
if(L==R){
a[u].val=v;
return ;
}
if(k<=M){
add(u*2,k,v);
}
else{
add(u*2+1,k,v);
}
pushup(u);
}
int find(int u,int l,int r){
int val1=0;
if(l<=a[u].l&&r>=a[u].r){
return a[u].val;
}
int mid=(a[u].l+a[u].r)/2;
if(l<=mid){
val1=(find(u*2,l,r)^val1);
}
if(r>mid){
val1=(find(u*2+1,l,r)^val1);
}
return val1;
}
void dfs1(int u,int fa,int depth){
dep[u]=depth;
f[u]=fa;
size[u]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v!=fa){
dfs1(v,u,depth+1);
size[u]+=size[v];
if(size[v]>size[son[u]]){
son[u]=v;
}
}
}
}
void dfs2(int u,int nowtop){
id[u]=++cnt;
valt[cnt]=val[u];
top[u]=nowtop;
if(son[u]){
dfs2(son[u],nowtop);
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v!=f[u]&&v!=son[u]){
dfs2(v,v);
}
}
}
}
void build(int u,int l,int r){
a[u].l=l;
a[u].r=r;
if(l==r){
a[u].val=valt[l];
a[u].val=a[u].val;
return;
}
int mid=(l+r)/2;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
a[u].val=(a[u*2].val^a[u*2+1].val);
}
int queryintree(int x,int y){
int sum=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
sum^=find(1,id[top[x]],id[x]);
x=f[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
sum^=find(1,id[x],id[y]);
return sum;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>val[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y;
cin>>op;
if(op==1){
cin>>x>>y;
add(1,x,y);
}
if(op==2){
cin>>x>>y;
cout<<queryintree(x,y)<<endl;
}
}
return 0;
}