#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, Q, u, v, x, opt, a[maxn];
int root;
struct Edge {
  int to, nex;
} edge[maxn << 1];
int head[maxn], ecnt;
void add_edge(int u, int v) {
  edge[++ecnt] = {v, head[u]};
  head[u] = ecnt;
}
int father[maxn], hson[maxn], siz[maxn], depth[maxn];
int dfu, dfn[maxn], rk[maxn], top[maxn];
struct Tree {
  long long tr[maxn << 2];
  long long tag[maxn << 2];
  void pushup(int p) { tr[p] = tr[p << 1] + tr[p << 1 | 1]; }
  void build(int p, int l, int r) {
    tag[p] = 0;
    if (l == r) {
      tr[p] = a[rk[l]];
      return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pushup(p);
  }
  void load(int p, int l, int r, long long k) {
    tag[p] += 1LL * k;
    tr[p] += 1LL * (r - l + 1) * k;
  }
  void pushdown(int p, int l, int r) {
    int mid = (l + r) >> 1;
    load(p << 1, l, mid, tag[p]);
    load(p << 1 | 1, mid + 1, r, tag[p]);
    tag[p] = 0;
  }
  void update(int nl, int nr, int l, int r, int p, long long k) {
    if (nl <= l && nr >= r) {
      load(p, l, r, k);
      return;
    }
    pushdown(p, l, r);
    int mid = (l + r) >> 1;
    if (nl <= mid) update(nl, nr, l, mid, p << 1, k);
    if (nr >= mid + 1) update(nl, nr, mid + 1, r, p << 1 | 1, k);
    pushup(p);
  }
  long long query(int nl, int nr, int l, int r, int p) {
    long long ret = 0LL;
    if (nl <= l && nr >= r) return tr[p];
    int mid = (l + r) >> 1;
    pushdown(p, l, r);
    if (nl <= mid) ret += query(nl, nr, l, mid, p << 1);
    if (nr >= mid + 1) ret += query(nl, nr, mid + 1, r, p << 1 | 1);
    return ret;
  }
} seg;
void get_hson(int now, int fa) {
  father[now] = fa;
  siz[now] = 1;
  depth[now] = depth[fa] + 1;
  int it = 0;
  for (int i = head[now]; i; i = edge[i].nex) {
    int to = edge[i].to;
    if (to == fa) continue;
    get_hson(to, now);
    siz[now] += siz[to];
    if (siz[to] > siz[it]) {
      hson[now] = to;
      it = to;
    }
  }
}
void dfs(int now, int thetop) {
  top[now] = thetop;
  dfn[now] = ++dfu;
  rk[dfn[now]] = now;
  if (siz[now] == 1) return;
  dfs(hson[now], thetop);
  for (int i = head[now]; i; i = edge[i].nex) {
    int to = edge[i].to;
    if (to == father[now] || to == hson[now]) continue;
    dfs(to, to);
  }
}
int get_lca(int u, int v) {
  int f1 = top[u], f2 = top[v];
  while (f1 != f2) {
    if (depth[f1] < depth[f2]) {
      swap(f1, f2);
      swap(u, v);
    }
    u = father[f1], f1 = top[u];
  }
  return depth[u] < depth[v] ? u : v;
}
int calc(int u) {
  int v = root;
  while (top[v] != top[u]) {
    if (father[top[v]] == u) return top[v];
    v = father[top[v]];
  }
  return hson[u];
}
int main() {
  scanf("%d %d", &n, &Q);
  for (int i = 1; i <= n; i++) scanf("%d", a + i);
  for (int i = 1; i < n; i++) {
    scanf("%d %d", &u, &v);
    add_edge(u, v);
    add_edge(v, u);
  }
  get_hson(1, 0);
  dfs(1, 1);
  root = 1;
  seg.build(1, 1, n);
  while (Q--) {
    scanf("%d", &opt);
    if (opt == 1) {
      scanf("%d", &u);
      root = u;
    } else if (opt == 2) {
      scanf("%d %d %d", &u, &v, &x);
      int lca = get_lca(u, v);
      int temp = get_lca(root, v);
      if (depth[temp] > depth[lca]) lca = temp;
      temp = get_lca(root, u);
      if (depth[temp] > depth[lca]) lca = temp;
      if (lca == root)
        seg.update(1, n, 1, n, 1, x);
      else if (dfn[lca] <= dfn[root] && dfn[root] <= dfn[lca] + siz[lca] - 1) {
        lca = calc(lca);
        seg.update(1, n, 1, n, 1, x);
        seg.update(dfn[lca], dfn[lca] + siz[lca] - 1, 1, n, 1, -x);
      } else
        seg.update(dfn[lca], dfn[lca] + siz[lca] - 1, 1, n, 1, x);
    } else {
      scanf("%d", &u);
      if (u == root)
        printf("%lld\n", seg.query(1, n, 1, n, 1));
      else if (dfn[u] <= dfn[root] && dfn[root] <= dfn[u] + siz[u] - 1) {
        u = calc(u);
        printf("%lld\n", seg.query(1, n, 1, n, 1) -
                             seg.query(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1));
      } else
        printf("%lld\n", seg.query(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1));
    }
  }
  return 0;
}
