RT
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
#define int long long
const int MAXN=1e5+10;
int tree[MAXN*8],tag[MAXN*8];
bool have_tag[MAXN*8];
int sz[MAXN],son[MAXN],idx[MAXN];
int fa[MAXN],topfa[MAXN],deep[MAXN];
bool used[MAXN];
int f[MAXN][30];
int tot;
int n,m;
int root;
vector<int> g[MAXN];
inline void push_down(int rt,int l,int r)
{
if(not have_tag[rt]) return ;
tree[rt]=tag[rt];
tag[rt*2]=tag[rt];
tag[rt*2+1]=tag[rt];
tag[rt]=0;
have_tag[rt*2]=true;
have_tag[rt*2+1]=true;
have_tag[rt]=false;
return ;
}
inline void push_up(int rt,int l,int r)
{
int mid=(l+r)/2;
push_down(rt,l,r);
push_down(rt*2,l,mid);
push_down(rt*2+1,mid+1,r);
tree[rt]=min(tree[rt*2],tree[rt*2+1]);
return ;
}
void update(int rt,int l,int r,int L,int R,int x)
{
push_down(rt,l,r);
if(L<=l && r<=R)
{
tag[rt]=x;
have_tag[rt]=true;
return ;
}
int mid=(l+r)/2;
if(L<=mid) update(rt*2,l,mid,L,R,x);
if(R>mid) update(rt*2+1,mid+1,r,L,R,x);
push_up(rt,l,r);
return ;
}
int query(int rt,int l,int r,int L,int R)
{
push_down(rt,l,r);
if(L<=l && r<=R) return tree[rt];
int mid=(l+r)/2;
int res=1e9;
if(L<=mid) res=min(res,query(rt*2,l,mid,L,R));
if(R>mid) res=min(res,query(rt*2+1,mid+1,r,L,R));
return res;
}
void DFS1(int now,int lst,int depth)
{
deep[now]=depth;
fa[now]=lst;
sz[now]=1;
f[now][0]=lst;
for(int i=1;i<=20;i++) f[now][i]=f[f[now][i-1]][i-1];
for(int i=0;i<g[now].size();i++)
{
int v=g[now][i];
if(v==lst) continue;
DFS1(v,now,depth+1);
sz[now]+=sz[v];
if(sz[v]>sz[son[now]]) son[now]=v;
}
return ;
}
void DFS2(int now,int lst,int top)
{
if(now==0) return ;
topfa[now]=top;
idx[now]=++tot;
used[now]=true;
DFS2(son[now],now,top);
for(int i=0;i<g[now].size();i++)
{
int v=g[now][i];
if(v==lst || used[v]) continue;
DFS2(v,now,v);
}
return ;
}
inline int LCA(int x,int y)
{
while(topfa[x]!=topfa[y])
{
int fax=topfa[x],fay=topfa[y];
if(deep[fay]>deep[fax])
{
swap(fax,fay);
swap(x,y);
}
x=fa[fax];
}
if(deep[y]>deep[x]) swap(x,y);
return y;
}
inline int New_son(int x)
{
int y=root;
for(int i=20;i>=0;i--) if(deep[y]-(1<<i)>deep[x]) y=f[y][i];
return y;
}
inline void update_range(int x,int y,int z)
{
while(topfa[x]!=topfa[y])
{
int fax=topfa[x],fay=topfa[y];
if(deep[fay]>deep[fax])
{
swap(fax,fay);
swap(x,y);
}
update(1,1,n,idx[fax],idx[x],z);
x=fa[fax];
}
if(deep[y]>deep[x]) swap(x,y);
update(1,1,n,idx[y],idx[x],z);
return ;
}
inline int query_New_root(int x)
{
if(x==root) return query(1,1,n,1,n);
int l=LCA(x,root);
if(l==x)
{
int s=New_son(x);
return min(query(1,1,n,1,idx[s]-1),query(1,1,n,idx[s]+sz[x],n));
}
else return query(1,1,n,idx[x],idx[x]+sz[x]-1);
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m;
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,0,1);
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
update(1,1,n,idx[i],idx[i],x);
}
cin>>root;
for(int i=1;i<=m;i++)
{
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
root=x;
}
if(op==2)
{
int x,y,z;
cin>>x>>y>>z;
update_range(x,y,z);
}
if(op==3)
{
int x;
cin>>x;
cout<<query_New_root(x)<<"\n";
}
}
return 0;
}