#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
long long n, q, op, root = 1;
long long a[maxn];
long long head[maxn], to[maxn << 1], nxt[maxn << 1], cnt;
inline void add(long long u, long long v) {
  nxt[++cnt] = head[u];
  to[cnt] = v;
  head[u] = cnt;
}
namespace Tree_chain_partition {
long long fa[maxn], son[maxn], size[maxn], dep[maxn], top[maxn];
void dfs1(long long u, long long f) {
  size[u] = 1;
  fa[u] = f;
  dep[u] = dep[f] + 1;
  for (register long long i = head[u]; i; i = nxt[i]) {
    long long v = to[i];
    if (v == f) continue;
    dfs1(v, u);
    size[u] += size[v];
    if (size[v] > size[son[u]]) son[u] = v;
  }
}
long long id[maxn], w[maxn], tot;
void dfs2(long long u, long long topf) {
  id[u] = ++tot;
  w[tot] = a[u];
  top[u] = topf;
  if (!son[u]) return;
  dfs2(son[u], topf);
  for (register long long i = head[u]; i; i = nxt[i]) {
    long long v = to[i];
    if (v == son[u] || v == fa[u]) continue;
    dfs2(v, v);
  }
}
inline long long lca(long long x, long long y) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    x = fa[top[x]];
  }
  return dep[x] < dep[y] ? x : y;
}
long long find(long long x, long long y) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    if (fa[top[x]] == y) return top[x];
    x = fa[top[x]];
  }
  return dep[x] < dep[y] ? son[x] : son[y];
}
inline long long LCA(long long x, long long y) {
  if (dep[x] > dep[y]) swap(x, y);
  if (lca(x, y) == x) {
    if (id[y] <= id[root] && id[root] <= id[y] + size[y] - 1) {
      return y;
    }
    if (lca(x, root) == x) return lca(root, y);
    return x;
  }
  if (id[root] >= id[x] && id[root] <= id[x] + size[x] - 1) return x;
  if (id[root] >= id[y] && id[root] <= id[y] + size[y] - 1) return y;
  if ((lca(x, root) == root && lca(x, y) == lca(root, y)) ||
      (lca(y, root) == root && lca(x, y) == lca(root, x))) {
    return root;
  }
  if (lca(x, root) == lca(y, root)) return lca(x, y);
  if (lca(x, y) != lca(x, root)) return lca(x, root);
  if (lca(x, y) != lca(y, root)) return lca(y, root);
}
}  // namespace Tree_chain_partition
using namespace Tree_chain_partition;
namespace SegmentTree {
struct SegmentTree {
  long long v, tag;
} st[maxn << 2];
inline void push_up(long long rt) {
  st[rt].v = st[rt << 1].v + st[rt << 1 | 1].v;
}
void build(long long rt, long long l, long long r) {
  st[rt].tag = 0;
  if (l == r) {
    st[rt].v = w[l];
    return;
  }
  long long mid = (l + r) >> 1;
  build(rt << 1, l, mid);
  build(rt << 1 | 1, mid + 1, r);
  push_up(rt);
}
inline void push_down(long long rt, long long l, long long r) {
  long long mid = (l + r) >> 1;
  st[rt << 1].v += st[rt].tag * (mid - l + 1);
  st[rt << 1 | 1].v += st[rt].tag * (r - mid);
  st[rt << 1].tag += st[rt].tag;
  st[rt << 1 | 1].tag += st[rt].tag;
  st[rt].tag = 0;
}
void modify(long long rt, long long l, long long r, long long ql, long long qr,
            long long val) {
  if (ql > r || qr < l) return;
  if (ql <= l && qr >= r) {
    st[rt].v += (r - l + 1) * val;
    st[rt].tag += val;
    return;
  }
  push_down(rt, l, r);
  long long mid = (l + r) >> 1;
  modify(rt << 1, l, mid, ql, qr, val);
  modify(rt << 1 | 1, mid + 1, r, ql, qr, val);
  push_up(rt);
}
long long query(long long rt, long long l, long long r, long long ql,
                long long qr) {
  if (ql > r || qr < l) return 0;
  if (ql <= l && qr >= r) return st[rt].v;
  push_down(rt, l, r);
  long long mid = (l + r) >> 1;
  return query(rt << 1, l, mid, ql, qr) +
         query(rt << 1 | 1, mid + 1, r, ql, qr);
}
void update(long long pos, long long val) {
  if (root == pos) {
    modify(1, 1, n, 1, n, val);
    return;
  }
  long long tmp = lca(root, pos);
  if (tmp != pos) {
    modify(1, 1, n, id[pos], id[pos] + size[pos] - 1, val);
  } else {
    long long loc = find(root, pos);
    modify(1, 1, n, 1, n, val);
    modify(1, 1, n, id[loc], id[loc] + size[loc] - 1, -val);
  }
}
long long ask(long long pos) {
  if (pos == root) return query(1, 1, n, 1, n);
  long long tmp = lca(pos, root);
  if (tmp != pos) {
    return query(1, 1, n, id[pos], id[pos] + size[pos] - 1);
  }
  long long loc = find(root, pos);
  return query(1, 1, n, 1, n) -
         query(1, 1, n, id[loc], id[loc] + size[loc] - 1);
}
}  // namespace SegmentTree
using namespace SegmentTree;
template <typename T>
inline void read(T &x) {
  x = 0;
  T f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + (ch ^ 48);
    ch = getchar();
  }
  x *= f;
}
signed main() {
  read(n);
  read(q);
  for (register long long i = 1; i <= n; i++) {
    read(a[i]);
  }
  for (register long long i = 1, u, v; i < n; i++) {
    read(u), read(v);
    add(u, v);
    add(v, u);
  }
  dfs1(1, 0);
  dfs2(1, 1);
  build(1, 1, n);
  while (q--) {
    read(op);
    if (op == 1) read(root);
    if (op == 2) {
      long long x, y, val;
      read(x), read(y), read(val);
      update(LCA(x, y), val);
    }
    if (op == 3) {
      long long x;
      read(x);
      printf("%lld\n", ask(x));
    }
  }
  return 0;
}
