/*
Author:wuhuajun
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
typedef double dd;
const int maxn=200010;
const ll INF = (ll)1E14 + 9;
int h[maxn], n, m, top[maxn], lca[maxn][21], son[maxn], edge, sz[maxn], dep[maxn];
int L[maxn], R[maxn], root, num, x, y, tx, ty, t, opt;
ll val, a[maxn];
struct Edge
{
int to, ne;
} e[maxn * 2];
struct Seg
{
ll minn, same;
} seg[maxn << 2];
void close()
{
exit(0);
}
void addedge(int x,int y)
{
e[edge].to = y;
e[edge].ne = h[x];
h[x] = edge++;
}
void dfs(int k,int from)
{
sz[k] = 1;
dep[k] = dep[from] + 1;
son[k] = 0;
for (int p=h[k];p!=-1;p=e[p].ne)
{
int to = e[p].to;
if (to == from) continue;
lca[to][0] = k;
for (int i=1;i<=20;i++)
lca[to][i] = lca[lca[to][i-1]][i-1];
dfs(to, k);
sz[k] += sz[to];
if (sz[to] > sz[son[k]]) son[k] = to;
}
}
void build(int k,int from)
{
L[k] = ++num;
top[k] = from;
if (son[k]) build(son[k], from);
for (int p=h[k];p!=-1;p=e[p].ne)
{
int to = e[p].to;
if (to != lca[k][0] && to != son[k])
build(to, to);
}
R[k] = num;
}
int get_lca(int x,int y)
{
if (dep[x] < dep[y]) swap(x, y);
int depth = dep[x] - dep[y];
for (int i=20;i>=0;i--)
if (depth & (1 << i))
x = lca[x][i];
if (x == y) return x;
for (int i=20;i>=0;i--)
{
if (lca[x][i] != lca[y][i])
{
x = lca[x][i];
y = lca[y][i];
}
}
return lca[x][0];
}
void pushup(int rt)
{
seg[rt].minn = min(seg[rt<<1].minn, seg[rt<<1|1].minn);
}
void same(int rt,ll val)
{
seg[rt].minn = val;
seg[rt].same = val;
}
void pushdown(int rt)
{
if (seg[rt].same)
{
same(rt << 1, seg[rt].same);
same(rt << 1 | 1, seg[rt].same);
seg[rt].same = 0;
}
}
void change(int L,int R,ll val,int l,int r,int rt)
{
if (L <= l && r <= R)
{
same(rt, val);
return;
}
int mid = (l + r) >> 1;
pushdown(rt);
if (L <= mid)
change(L,R,val,lson);
if (mid + 1 <= R)
change(L,R,val,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if (L > R) return INF;
if (L <= l && r <= R)
{
return seg[rt].minn;
}
int mid = (l + r) >> 1;
pushdown(rt);
ll ans = INF;
if (L <= mid)
ans = min(ans, query(L,R,lson));
if (mid + 1 <= R)
ans = min(ans, query(L,R,rson));
pushup(rt);
return ans;
}
void cc()
{
tx = top[x];
ty = top[y];
while (tx != ty)
{
if (dep[tx] < dep[ty])
{
swap(x, y);
swap(tx, ty);
}
change(L[tx], L[x], val, 1, n, 1);
x = lca[tx][0];
tx = top[x];
}
if (dep[x] < dep[y])
swap(x, y);
change(L[y], L[x], val, 1, n, 1);
}
void work()
{
if (root == x)
{
printf("%lld\n", seg[1].minn);//询问全局的
return;
}
t = get_lca(root, x);
if (t != x) //表示不在它到根的路径上
{
printf("%lld\n", query(L[x], R[x], 1, n, 1));
return;
}
int depth = dep[root] - dep[x] - 1;
int haha = root;
for (int i=20;i>=0;i--)
if (depth & (1 << i))
haha = lca[haha][i];
printf("%lld\n", min(query(1, L[haha] - 1, 1, n, 1), query(R[haha] + 1, n, 1, n, 1)) );
}
void init()
{
scanf("%d %d",&n,&m);
memset(h, -1, sizeof(h));
for (int i=1;i<=n-1;i++)
{
scanf("%d %d",&x, &y);
addedge(x, y);
addedge(y, x);
}
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
dfs(1, 0);
build(1, 1);
/*
for (int i=1;i<=n;i++)
printf("i:%d top:%d hash:%d son:%d\n",i, top[i], L[i], son[i]);
close();
*/
for (int i=1;i<=n;i++)
change(L[i], L[i], a[i], 1, n, 1);
scanf("%d",&root);
while (m--)
{
scanf("%d",&opt);
if (opt == 1) scanf("%d",&root);
if (opt == 2)
{
scanf("%d %d %lld",&x,&y,&val);
cc();
}
if (opt == 3)
{
scanf("%d",&x);
work();
}
}
}
int main ()
{
init();
close();
return 0;
}