RT
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
#define N 100010
#define M 1010
using namespace std;
const int inf = 9000000000000000000;
int n, m, root;
int dep[N], top[N], siz[N], fath[N], son[N], dfn[N], w[N], pre[N], zu[N][20];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
namespace Seg {
#define lson rt << 1
#define rson rt << 1 | 1
struct node {
int min, lazy;
}tree[N << 2];
void push_up(int rt) {
tree[rt].min = min(tree[lson].min, tree[rson].min);
}
void build(int rt, int l, int r) {
tree[rt].lazy = -1;
if (l == r) {
tree[rt].min = w[pre[l]];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
push_up(rt);
}
void push_down(int rt) {
if (tree[rt].lazy == -1) return;
tree[lson].min = tree[rson].min = tree[rt].lazy;
tree[lson].lazy = tree[rson].lazy = tree[rt].lazy;
tree[rt].lazy = -1;
}
void updata(int rt, int val, int l, int r, int L, int R) {
if (L <= l && r <= R) {
tree[rt].min = tree[rt].lazy = val;
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if (L <= mid) updata(lson, val, l, mid, L, R);
if (R > mid) updata(rson, val, mid + 1, r, L, R);
push_up(rt);
}
int query(int rt, int l, int r, int L, int R) {
if (L <= l && r <= R) return tree[rt].min;
push_down(rt);
int mid = (l + r) >> 1, ans = inf;
if (L <= mid) ans = min(ans, query(lson, l, mid, L, R));
if (R > mid) ans = min(ans, query(rson, mid + 1, r, L, R));
return ans;
}
}
namespace Cut {
int cnt, add_edge, head[N << 1];
struct node {
int next, to;
}edge[N << 1];
void add(int from, int to) {
edge[++add_edge].next = head[from];
edge[add_edge].to = to;
head[from] = add_edge;
}
void dfs(int x, int fa) {
siz[x] = 1, fath[x] = fa, dep[x] = dep[fa] + 1, zu[x][0] = fa;
for (int i = 1; i <= 18; i++) {
zu[x][i] = zu[zu[x][i - 1]][i - 1];
if (!zu[x][i]) break;
}
for (int i = head[x]; i; i = edge[i].next) {
int to = edge[i].to;
if (to == fa) continue;
dfs(to, x), siz[x] += siz[to];
if (siz[son[x]] < siz[to]) son[x] = to;
}
}
void dfs2(int x, int tp) {
dfn[x] = ++cnt, pre[cnt] = x, top[x] = tp;
if (son[x]) dfs2(son[x], tp);
for (int i = head[x]; i; i = edge[i].next) {
int to = edge[i].to;
if (to == son[x] || to == fath[x]) continue;
dfs2(to, to);
}
}
void change(int x, int y, int val) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
Seg::updata(1, val, 1, n, dfn[top[x]], dfn[x]);
x = fath[top[x]];
}
if (dfn[x] > dfn[y]) swap(x, y);
Seg::updata(1, val, 1, n, dfn[x], dfn[y]);
}
int getfa(int x, int sum) {
for (int i = 18; i >= 0; --i)
if (sum >= (1 << i))
x = zu[x][i], sum -= (1 << i);
return x;
}
}
signed main() {
// freopen("out.txt", "w", stdout);
n = read(), m = read();
for (int i = 1, x, y; i < n; i++) {
x = read(), y = read();
Cut::add(x, y), Cut::add(y, x);
}
for (int i = 1; i <= n; i++) w[i] = read();
Cut::dfs(1, 0), Cut::dfs2(1, 1), Seg::build(1, 1, n);
root = read();
int sy = 0;
for (int i = 1, opt, x, y, val; i <= m; i++) {
opt = read();
if (opt == 1) root = read();
if (opt == 2) {
x = read(), y = read(), val = read();
Cut::change(x, y, val);
}
if (opt == 3) {
x = read();
if (x == root) printf("%lld\n", Seg::tree[1].min);
else if (dep[x] < dep[root] && zu[y = Cut::getfa(root, dep[root] - dep[x] + 1)][0] == x) {
// y = fath[y];
int p = Seg::query(1, 1, n, 1, dfn[y] - 1), q;
if (dfn[y] + siz[y] <= n) q = Seg::query(1, 1, n, dfn[y] + siz[y], n);
else q = inf;
printf("%lld\n", min(p, q));
} else printf("%lld\n", Seg::query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1));
}
}
}
/*
5 8
1 2
2 3
3 4
4 5
1 2 3 4 5
1
3 1
2 1 4 2
1 3
3 4
3 5
1 4
2 3 4 3
3 3
*/