#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e7 + 5;
int n, m, a[maxn];
struct Node{
int to, next;
}e[maxn];
int len, head[maxn];
void Insert(int u, int v){
e[++len].to = v; e[len].next = head[u]; head[u] = len;
}
int cnt, dfn[maxn], rk[maxn], deep[maxn], siz[maxn], son[maxn], top[maxn], f[maxn];
void dfs1(int u){
siz[u] = 1; deep[u] = deep[f[u]] + 1;
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to;
if(v == f[u]) continue;
f[v] = u;
dfs1(v);
siz[u] += siz[v];
if(!son[u] or siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int fa){
top[u] = fa;
dfn[u] = ++cnt;
rk[cnt] = u;
if( son[u]) dfs2(son[u], fa);
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to;
if(v != f[u] and v != son[u]) dfs2(v, v);
}
}
//以上为剖分
int tr[maxn], lazy[maxn];
void pushup(int rt) {tr[rt] = min(tr[rt << 1], tr[rt << 1 | 1]);}
void pushdown(int rt){
if( lazy[rt]){
lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
tr[rt << 1] = tr[rt << 1 | 1] = lazy[rt];
lazy[rt] = 0;
}
}
void Build(int rt, int l, int r){
if(l == r){
tr[rt] = a[rk[l]];
return;
}
int mid = l + r >> 1;
Build(rt << 1, l, mid); Build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, int L, int R, int val){
if(L <= l and r <= R){
lazy[rt] = val;
tr[rt] = val;
return;
}
int mid = l + r >> 1;
pushdown(rt);
if(L <= mid) update(rt << 1, l, mid, L, R, val);
if(R > mid) update(rt << 1 | 1, mid + 1, r, L, R, val);
pushup(rt);
}
int query(int rt, int l, int r, int L, int R){
if(L <= l and r <= R) return tr[rt];
int mid = l + r >> 1, minn = 1e9;
pushdown(rt);
if(L <= mid) minn = min(minn, query(rt << 1, l, mid, L, R));
if(R > mid) minn = min(minn, query(rt << 1 | 1, mid + 1, r, L, R));
return minn;
}
//以上为线段树
void updatetree(int u, int v, int val){
while(top[u] != top[v]){
if(deep[top[u]] < deep[top[v]]) u ^= v ^= u ^= v;
update(1, 1, n, dfn[top[u]], dfn[u], val);
u = f[top[u]];
}
if(deep[u] > deep[v]) u ^= v ^= u ^= v;
update(1, 1, n, dfn[u], dfn[v], val);
}
//小修改
int root;
int Find(int x, int rt){
while(top[x] != top[rt]){
if(f[top[rt]] == x) return top[rt];
rt = f[top[rt]];
}
return son[x];
}
//找直系儿子
void Solve(){
cin>>n>>m;
for(int i = 1; i < n; ++i){
int u, v; cin>>u>>v;
Insert(u, v); Insert(v, u);
}
for(int i = 1; i <= n; ++i) cin>>a[i];
cin>>root;
dfs1(1); dfs2(1, 1); Build(1, 1, n);
while(m--){
int op; cin>>op;
if(op == 1) cin>>root;
if(op == 2){
int u, v, val; cin>>u>>v>>val;
updatetree(u, v, val);
}
//因该是这下面错了吧,调了很久都不对
if(op == 3){
int x; cin>>x;
if(x == root) cout<<tr[1]<<endl;
else if(dfn[root] <= dfn[x] or dfn[root] > dfn[x] + siz[x] - 1) cout<<query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1)<<endl;
else{
int y = Find(x, root);
int ans = query(1, 1, n, 1, dfn[y] - 1);
if(dfn[y] + siz[y] - 1 != n) ans = min(ans, query(1, 1, n, dfn[y] + siz[y], n));
cout<<ans<<endl;
}
}
}
}
signed main(){
Solve();
return 0;
}