rt.
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=-1;
int n,m;
int k;
struct node{
int opt;
unsigned long long val;
}a[1000005];
struct Node{
int nex,to;
}e[1000005];
int tot;
int he[1000005];
inline void add(int x,int y){
e[++tot].nex=he[x];
e[tot].to=y;
he[x]=tot;
}
int son[1000005];
int siz[1000005];
int fa[1000005];
int dep[1000005];
inline void dfs(int x,int f){
int maxn=0;
siz[x]=1;
fa[x]=f;
dep[x]=dep[f]+1;
int maxtep=0;
for (int i=he[x];i;i=e[i].nex){
int v=e[i].to;
if (v==f) continue;
dfs(v,x);
siz[x]+=siz[v];
if (siz[v]>maxn){
maxn=siz[v];
maxtep=v;
}
}
son[x]=maxtep;
}
int id[1000005];
int w[1000005];
int t[1000005];
int ID;
inline void DFS(int x,int top){
ID++;
w[ID]=x;
t[x]=top;
id[x]=ID;
if (!son[x]){
return;
}
DFS(son[x],top);
for (int i=he[x];i;i=e[i].nex){
int v=e[i].to;
if (v==fa[x] || v==son[x]) continue;
DFS(v,v);
}
}
struct NODE{
unsigned long long f,ff,iv,ivv;
}tree[1000005];
inline unsigned long long F(int x,int id){
if (a[id].opt==1){
return x&a[id].val;
}
if (a[id].opt==2){
return x|a[id].val;
}
return x^a[id].val;
}
inline void update(int p){
tree[p].f=((tree[p<<1].f&tree[p<<1|1].ff)|((~tree[p<<1].f)&tree[p<<1|1].f));
tree[p].ff=((tree[p<<1].ff&tree[p<<1|1].ff)|((~tree[p<<1].ff)&tree[p<<1|1].f));
tree[p].iv=((tree[p<<1|1].iv&tree[p<<1].ivv)|((~tree[p<<1|1].iv)&tree[p<<1].iv));
tree[p].ivv=((tree[p<<1|1].ivv&tree[p<<1].ivv)|((~tree[p<<1|1].ivv)&tree[p<<1].iv));
}
inline void build(int p,int l,int r){
if (l==r){
tree[p].f=tree[p].iv=F(0,w[l]);
tree[p].ff=tree[p].ivv=F(N,w[l]);
return;
}
int mid=(l+r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
update(p);
}
inline void change(int p,int l,int r,int pos){
if (l==r){
tree[p].f=tree[p].iv=F(0,w[l]);
tree[p].ff=tree[p].ivv=F(N,w[l]);
return;
}
int mid=(l+r)/2;
if (mid>=pos){
change(p<<1,l,mid,pos);
}
else{
change(p<<1|1,mid+1,r,pos);
}
update(p);
}
NODE a1[1000005];
NODE a2[1000005];
int top1;
int top2;
inline NODE take(NODE l,NODE r){
NODE res;
res.f=((l.f&r.ff)|((~l.f)&r.f));
res.ff=((l.ff&r.ff)|((~l.ff)&r.f));
res.iv=((r.iv&l.ivv)|((~r.iv)&l.iv));
res.ivv=((r.ivv&l.ivv)|((~r.ivv)&l.iv));
return res;
}
inline NODE ask(int p,int l,int r,int L,int R){
if (L==l && r==R){
return tree[p];
}
int mid=(l+r)/2;
NODE ans;
if (mid>=R){
ans=ask(p<<1,l,mid,L,R);
}
else if (mid<L){
ans=ask(p<<1|1,mid+1,r,L,R);
}
else{
ans=take(ask(p<<1,l,mid,L,mid),ask(p<<1|1,mid+1,r,mid+1,R));
}
return ans;
}
inline NODE query(int x,int y){
top1=0;
top2=0;
while (t[x]!=t[y]){
if (dep[t[x]]>=dep[t[y]]){
a1[++top1]=ask(1,1,n,id[t[x]],id[x]);
x=fa[t[x]];
}
else{
a2[++top2]=ask(1,1,n,id[t[y]],id[y]);
y=fa[t[y]];
}
}
if (dep[x]>dep[y]){
a1[++top1]=ask(1,1,n,id[y],id[x]);
}
else{
a2[++top2]=ask(1,1,n,id[x],id[y]);
}
for (int i=1;i<=top1;i++){
swap(a1[i].f,a1[i].iv);
swap(a1[i].ff,a1[i].ivv);
}
NODE ans;
if (top1){
ans=a1[1];
for (int i=2;i<=top1;i++){
ans=take(ans,a1[i]);
}
if (top2){
ans=take(ans,a2[top2]);
}
}
else{
ans=a2[top2];
}
for (int i=top2-1;i>=1;i--){
ans=take(ans,a2[i]);
}
return ans;
}
signed main(){
cin>>n>>m>>k;
for (int i=1;i<=n;i++){
cin>>a[i].opt>>a[i].val;
}
for (int i=1;i<n;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
dfs(1,0);
DFS(1,0);
build(1,1,n);
while (m--){
int op,x,y,z;
cin>>op>>x>>y>>z;
if (op==2){
a[x].opt=y;
a[x].val=z;
change(1,1,n,id[x]);
}
else{
NODE ans=query(x,y);
int res=0;
for (int i=63;~i;i--){
int u=(ans.f>>i)&1ull;
int v=(ans.ff>>i)&1ull;
if (u>=v || (1ull<<i)>z){
if (u){
res+=(1ull<<i);
}
}
else{
if (v){
res+=(1ull<<i);
}
z-=(1ull<<i);
}
}
cout<<res<<"\n";
}
}
return 0;
}