#include <bits/stdc++.h>
using namespace std;
inline long long read() {
  long long x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = (x << 1) + (x << 3) + ch - '0';
    ch = getchar();
  }
  return x * f;
}
struct edge {
  int v, next;
} e[100005 << 1];
int head[100005], k;
inline void add(int u, int v) {
  e[k] = (edge){v, head[u]};
  head[u] = k++;
}
int N, Q, rt = 1;
long long a[100005];
int size[100005], son[100005], dfn[100005], rnk[100005], top[100005], dfs_cnt,
    dep[100005], fa[100005];
inline void dfs1(int u, int f) {
  fa[u] = f;
  dep[u] = dep[f] + 1;
  size[u] = 1;
  son[u] = -1;
  for (register int i = head[u]; ~i; i = e[i].next) {
    int v = e[i].v;
    if (v == f) continue;
    dfs1(v, u);
    size[u] += size[v];
    if (son[u] == -1 || size[v] > size[son[u]]) son[u] = v;
  }
}
inline void dfs2(int u, int t) {
  dfn[u] = ++dfs_cnt;
  rnk[dfn[u]] = u;
  top[u] = t;
  if (son[u] == -1) return;
  dfs2(son[u], t);
  for (register int i = head[u]; ~i; i = e[i].next) {
    int v = e[i].v;
    if (dfn[v]) continue;
    dfs2(v, v);
  }
}
inline int LCA(int a, int b) {
  while (top[a] != top[b]) {
    if (dep[top[a]] < dep[top[b]]) swap(a, b);
    a = fa[top[a]];
  }
  return dep[a] < dep[b] ? a : b;
}
inline int find(int a, int b) {
  while (top[a] != top[b]) {
    if (fa[top[a]] == b) return top[a];
    a = fa[top[a]];
  }
  return son[b];
}
struct node {
  int l, r;
  long long sum, lazy;
} tree[100005 << 3];
inline void build(int p, int l, int r) {
  tree[p] = (node){l, r, 0, 0};
  if (l == r) {
    tree[p].sum = a[rnk[l]];
    return;
  }
  int mid = (l + r) >> 1;
  build((p << 1), l, mid);
  build((p << 1 | 1), mid + 1, r);
  tree[p].sum = tree[(p << 1)].sum + tree[(p << 1 | 1)].sum;
}
inline void add(int p, long long d) {
  if (!p) return;
  tree[p].sum += 1ll * (tree[p].r - tree[p].l + 1) * d;
  tree[p].lazy += d;
}
inline void push_down(int p) {
  if (!p || !tree[p].lazy) return;
  add((p << 1), tree[p].lazy);
  add((p << 1 | 1), tree[p].lazy);
  tree[p].lazy = 0;
}
inline void update(int p, int L, int R, long long d) {
  int l = tree[p].l, r = tree[p].r;
  if (L <= l && r <= R) {
    add(p, d);
    return;
  }
  push_down(p);
  int mid = (l + r) >> 1;
  if (L <= mid) update((p << 1), L, R, d);
  if (R > mid) update((p << 1 | 1), L, R, d);
  tree[p].sum = tree[(p << 1)].sum + tree[(p << 1 | 1)].sum;
}
inline long long query(int p, int L, int R) {
  int l = tree[p].l, r = tree[p].r;
  if (L <= l && r <= R) return tree[p].sum;
  push_down(p);
  int mid = (l + r) >> 1;
  long long ans = 0;
  if (L <= mid) ans += query((p << 1), L, R);
  if (R > mid) ans += query((p << 1 | 1), L, R);
  return ans;
}
inline void Case2(int u, int v, long long d) {
  int l1 = LCA(u, v), l2 = LCA(u, rt), l3 = LCA(v, rt);
  int lca = dep[l1] > dep[l2] ? l1 : l2;
  lca = dep[lca] > dep[l3] ? lca : l3;
  if (lca == rt)
    update(1, 1, N, d);
  else if (dfn[rt] < dfn[lca] || dfn[rt] > dfn[lca] + size[lca] - 1)
    update(1, dfn[lca], dfn[lca] + size[lca] - 1, d);
  else {
    int f = find(rt, lca);
    update(1, 1, N, d);
    update(1, dfn[f], dfn[f] + size[f] - 1, -d);
  }
}
inline long long Case3(int u) {
  if (rt == u)
    return query(1, 1, N);
  else if (dfn[rt] < dfn[u] || dfn[rt] > dfn[u] + size[u] - 1)
    return query(1, dfn[u], dfn[u] + size[u] - 1);
  else {
    int f = find(rt, u);
    return query(1, 1, N) - query(1, dfn[f], dfn[f] + size[f] - 1);
  }
}
int main() {
  N = read(), Q = read();
  for (register int i = 1; i <= N; ++i) a[i] = read();
  memset(head, -1, sizeof head);
  for (register int i = 1; i < N; ++i) {
    int u = read(), v = read();
    add(u, v);
    add(v, u);
  }
  dfs1(1, 0);
  dfs2(1, 1);
  build(1, 1, N);
  while (Q--) {
    int opt = read();
    if (opt == 1)
      rt = read();
    else if (opt == 2) {
      int u = read(), v = read();
      Case2(u, v, read());
    } else
      printf("%lld\n", Case3(read()));
  }
  return 0;
}
