#include <bits/stdc++.h>
using namespace std;
template <typename T>
void read(T &x) {
  x = 0;
  char r = getchar();
  T neg = 1;
  while (!((r >= '0' && r <= '9'))) {
    if (r == 45) neg = -1;
    r = getchar();
  }
  while (((r >= '0' && r <= '9'))) {
    x = (x << 1) + (x << 3) + r - 48;
    r = getchar();
  }
  x *= neg;
}
int n, m, root = 1;
const int maxn = 100000 + 10;
int a[maxn];
struct node {
  int e;
  int nxt;
} edge[maxn << 1];
int cnt = 0, head[maxn];
inline void addl(int u, int v) {
  edge[cnt].e = v;
  edge[cnt].nxt = head[u];
  head[u] = cnt++;
}
int dep[maxn], fa[maxn], siz[maxn], son[maxn];
void dfs1(int u, int f) {
  dep[u] = dep[f] + 1;
  fa[u] = f;
  siz[u] = 1;
  son[u] = 0;
  for (int i = head[u]; i != -1; i = edge[i].nxt) {
    int v = edge[i].e;
    if (v == f) continue;
    dfs1(v, u);
    siz[u] += siz[v];
    son[u] = ((siz[son[u]] > siz[v]) ? son[u] : v);
  }
}
int seg[maxn], rev[maxn], top[maxn];
void dfs2(int u) {
  if (son[u]) {
    seg[son[u]] = ++seg[0];
    rev[seg[0]] = son[u];
    top[son[u]] = top[u];
    dfs2(son[u]);
  }
  for (int i = head[u]; i != -1; i = edge[i].nxt) {
    int v = edge[i].e;
    if (!top[v]) {
      top[v] = v;
      seg[v] = ++seg[0];
      rev[seg[0]] = v;
      dfs2(v);
    }
  }
}
long long sum[maxn << 2], lazy[maxn << 2];
inline void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; }
inline void pushdown(int l, int r, int rt) {
  if (lazy[rt]) {
    lazy[rt << 1] += lazy[rt];
    lazy[rt << 1 | 1] += lazy[rt];
    int mid = (l + r) >> 1;
    sum[rt << 1] += lazy[rt] * (mid - l + 1);
    sum[rt << 1 | 1] += lazy[rt] * (r - (mid + 1) + 1);
    lazy[rt] = 0;
  }
}
void buildtree(int l, int r, int rt) {
  if (l > r) return;
  if (l == r) {
    sum[rt] = a[rev[l]];
    return;
  }
  int mid = (l + r) >> 1;
  buildtree(l, mid, rt << 1);
  buildtree(mid + 1, r, rt << 1 | 1);
  pushup(rt);
}
void update(int l, int r, int nl, int nr, int rt, long long w) {
  if (l > r || nl > nr) return;
  if (l <= nl && nr <= r) {
    sum[rt] += (nr - nl + 1) * w;
    lazy[rt] += w;
    return;
  }
  pushdown(nl, nr, rt);
  int mid = (nl + nr) >> 1;
  if (mid >= l) update(l, r, nl, mid, rt << 1, w);
  if (mid < r) update(l, r, mid + 1, nr, rt << 1 | 1, w);
  pushup(rt);
}
long long query(int l, int r, int nl, int nr, int rt) {
  if (l > r || nl > nr) return 0;
  if (l <= nl && nr <= r) return sum[rt];
  int mid = (nl + nr) >> 1;
  pushdown(nl, nr, rt);
  long long res = 0;
  if (mid >= l) res += query(l, r, nl, mid, rt << 1);
  if (mid < r) res += query(l, r, mid + 1, nr, rt << 1 | 1);
  return res;
}
inline int lca(int u, int v) {
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) swap(u, v);
    u = fa[top[u]];
  }
  return ((dep[u] < dep[v]) ? u : v);
}
inline void updateline(int u, int v, long long w) {
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) swap(u, v);
    update(seg[top[u]], seg[u], 1, seg[0], 1, w);
    u = fa[top[u]];
  }
  if (dep[u] < dep[v]) swap(u, v);
  update(seg[v], seg[u], 1, seg[0], 1, w);
}
inline int find(int u, int v) {
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) swap(u, v);
    if (fa[top[u]] == v) return top[u];
    u = fa[top[u]];
  }
  if (dep[u] < dep[v]) swap(u, v);
  return son[v];
}
inline void updateson(int u, long long w) {
  if (root == u) {
    update(1, seg[0], 1, seg[0], 1, w);
    return;
  }
  int LCA = lca(u, root);
  if (LCA != u) {
    update(seg[u], seg[u] + siz[u] - 1, 1, seg[0], 1, w);
    return;
  }
  int x = find(u, root);
  update(1, seg[0], 1, seg[0], 1, w);
  update(seg[x], seg[x] + siz[x] - 1, 1, seg[0], 1, -w);
}
inline long long queryline(int u, int v) {
  long long res = 0;
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) swap(u, v);
    res += query(seg[top[u]], seg[u], 1, seg[0], 1);
    u = fa[top[u]];
  }
  if (dep[u] < dep[v]) swap(u, v);
  res += query(seg[v], seg[u], 1, seg[0], 1);
  return res;
}
inline long long queryson(int u) {
  if (root == u) return query(1, seg[0], 1, seg[0], 1);
  int LCA = lca(u, root);
  if (LCA != u) return query(seg[u], seg[u] + siz[u] - 1, 1, seg[0], 1);
  int x = find(u, root);
  return query(1, seg[0], 1, seg[0], 1) -
         query(seg[x], seg[x] + siz[x] - 1, 1, seg[0], 1);
}
int lca_(int ui, int vi) {
  int a1 = lca(ui, vi);
  int a2 = lca(ui, root);
  int a3 = lca(vi, root);
  return (dep[(dep[a2] > dep[a1] ? a2 : a1)] > dep[a3]
              ? ((dep[a2] > dep[a1] ? a2 : a1))
              : a3);
}
int main() {
  memset(head, -1, sizeof(head));
  read(n);
  read(m);
  for (register int i = 1; i <= n; ++i) read(a[i]);
  for (register int i = 1; i <= n - 1; ++i) {
    int ui, vi;
    read(ui);
    read(vi);
    addl(ui, vi);
    addl(vi, ui);
  }
  dfs1(1, 0);
  seg[0] = seg[1] = top[1] = rev[1] = 1;
  dfs2(1);
  buildtree(1, seg[0], 1);
  for (register int i = 1; i <= m; ++i) {
    int op;
    read(op);
    if (op == 1)
      read(root);
    else if (op == 2) {
      int ui, vi, ki;
      read(ui), read(vi), read(ki);
      updateson(lca_(ui, vi), (long long)ki);
    } else if (op == 3) {
      int ui;
      read(ui);
      printf("%I64d\n", queryson(ui));
    }
  }
  return 0;
}
