#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
vector<long long> G[100010];
long long fa[100010];
long long dp[100010];
long long sz[100010];
long long sn[100010];
long long dfn[100010];
long long tp[100010];
long long tree[100010];
long long a[100010];
long long val[400010];
long long flag[400010];
long long cnt, n, m, root;
long long dfs(long long u)
{
dp[u] = dp[fa[u]] + 1;
sz[u] = 1;
for(long long v : G[u])
{
if(fa[u] != v)
{
fa[v] = u;
dfs(v);
sz[u] += sz[v];
if(sz[v] > sz[sn[u]])
{
sn[u] = v;
}
}
}
return 0;
}
long long dfs2(long long u, long long t)
{
dfn[u] = ++cnt;
a[cnt] = tree[u];
tp[u] = t;
if(sn[u])
{
dfs2(sn[u], t);
}
for(long long v : G[u])
{
if(fa[u] != v && sn[u] != v)
{
dfs2(v, v);
}
}
return 0;
}
long long pushdown(long long o, long long l, long long r)
{
if(flag[o])
{
val[o << 1] = flag[o];
val[o << 1 | 1] = flag[o];
flag[o << 1] = flag[o];
flag[o << 1 | 1] = flag[o];
flag[o] = 0;
}
}
long long build(long long o, long long l, long long r)
{
if(l == r)
{
val[o] = a[l];
return 0;
}
long long mid = l + r >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
val[o] = min(val[o << 1], val[o << 1 | 1]);
return 0;
}
long long set(long long o, long long l, long long r, long long s, long long t, long long k)
{
if(s <= l && r <= t)
{
val[o] = k;
flag[o] = k;
return 0;
}
pushdown(o, l, r);
long long mid = l + r >> 1;
if(s <= mid)
{
set(o << 1, l, mid, s, t, k);
}
if(mid < t)
{
set(o << 1 | 1, mid + 1, r, s, t, k);
}
val[o] = min(val[o << 1], val[o << 1 | 1]);
return 0;
}
long long query(long long o, long long l, long long r, long long s, long long t)
{
if(s <= l && r <= t)
{
return val[o];
}
pushdown(o, l, r);
long long mid = l + r >> 1;
long long ans = 21474836470000;
if(s <= mid)
{
ans = min(ans, query(o << 1, l, mid, s, t));
}
if(mid < t)
{
ans = min(ans, query(o << 1 | 1, mid + 1, r, s, t));
}
return ans;
}
long long setpath(long long u, long long v, long long k)
{
while(tp[u] != tp[v])
{
if(dp[tp[u]] < dp[tp[v]])
{
swap(u, v);
}
set(1, 1, n, dfn[tp[u]], dfn[u], k);
u = fa[tp[u]];
}
if(dp[u] > dp[v])
{
swap(u, v);
}
set(1, 1, n, dfn[u], dfn[v], k);
return 0;
}
long long querytree(long long u)
{
return query(1, 1, n, dfn[u], dfn[u] + sz[u] - 1);
}
long long find(long long u)
{
long long now = root;
while(tp[now] != tp[u])
{
if(fa[tp[now]] == u)
{
return tp[now];
}
now = fa[tp[now]];
}
return sn[u];
}
int main()
{
scanf("%lld%lld", &n, &m);
for(long long i = 1; i < n; i++)
{
long long u, v;
scanf("%lld%lld", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for(long long i = 1; i <= n; i++)
{
scanf("%lld", &tree[i]);
}
dfs(1);
dfs2(1, 1);
build(1, 1, n);
scanf("%lld", &root);
for(long long i = 1; i <= m; i++)
{
long long op;
scanf("%lld", &op);
if(op == 1)
{
scanf("%lld", &root);
}
if(op == 2)
{
long long u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
setpath(u, v, w);
}
else
{
long long u;
scanf("%lld", &u);
if(u == root)
{
printf("%lld\n", val[1]);
}
else if(dfn[root] <= dfn[u] || dfn[u] + sz[u] <= dfn[root])
{
printf("%lld\n", querytree(u));
}
else
{
long long x = find(u);
long long ans = query(1, 1, n, 1, dfn[x] - 1);
if(dfn[x] + sz[x] - 1 != n)
{
ans = min(ans, query(1, 1, n, dfn[x] + sz[x], n));
}
printf("%lld\n", ans);
}
}
}
}