#include <bits/stdc++.h>
using namespace std;
int N, Q, R;
vector<int> Adj[100005];
int w[100005], wid[100005];
int dep[100005], size[100005], son[100005], fa[100005], top[100005];
int anc[100005][21];
void dfs1(int u) {
  size[u] = 1;
  for (int j = 1; j <= 20; j++) {
    if (dep[u] <= (1 << j)) break;
    anc[u][j] = anc[anc[u][j - 1]][j - 1];
  }
  int v, m1 = -1;
  for (int k = 0; k < Adj[u].size(); k++) {
    v = Adj[u][k];
    if (v == fa[u]) continue;
    dep[v] = dep[u] + 1;
    fa[v] = u;
    anc[v][0] = u;
    dfs1(v);
    size[u] += size[v];
    if (m1 < size[v]) {
      m1 = size[v];
      son[u] = v;
    }
  }
}
int tt = 0;
int id[100005];
void dfs2(int u, int x) {
  id[u] = ++tt;
  wid[tt] = w[u];
  top[u] = x;
  if (!son[u]) return;
  dfs2(son[u], x);
  int v;
  for (int k = 0; k < Adj[u].size(); k++) {
    v = Adj[u][k];
    if (v == fa[u] || v == son[u]) continue;
    dfs2(v, v);
  }
}
struct Node {
  int l, r;
  long long d, tag;
  Node *rs, *ls;
} pool[4 * 100005], *rt;
int topPool = 0;
long long getD(Node* p) {
  if (!p) return 0;
  return p->d + p->tag * (p->r - p->l + 1);
}
Node* buildT(int l, int r) {
  Node* p = pool + (++topPool);
  p->l = l;
  p->r = r;
  if (l == r) {
    p->d = wid[l];
    return p;
  }
  int mid = (l + r) / 2;
  p->ls = buildT(l, mid);
  p->rs = buildT(mid + 1, r);
  p->d = p->ls->d + p->rs->d;
  return p;
}
void pushD(Node* p) {
  if (!p->tag) return;
  p->d = getD(p);
  p->ls->tag += p->tag;
  p->rs->tag += p->tag;
  p->tag = 0;
}
long long query(Node* p, int l, int r) {
  if (p->l == l && p->r == r) return getD(p);
  pushD(p);
  int mid = (p->l + p->r) / 2;
  if (r <= mid)
    return query(p->ls, l, r);
  else if (l >= mid + 1)
    return query(p->rs, l, r);
  else {
    long long ans1 = query(p->ls, l, mid);
    long long ans2 = query(p->rs, mid + 1, r);
    return ans1 + ans2;
  }
}
void change(Node* p, int l, int r, int dx) {
  if (p->l == l && p->r == r) {
    p->tag += dx;
    return;
  }
  pushD(p);
  int mid = (p->l + p->r) / 2;
  if (r <= mid)
    change(p->ls, l, r, dx);
  else if (l >= mid + 1)
    change(p->rs, l, r, dx);
  else {
    change(p->ls, l, mid, dx);
    change(p->rs, mid + 1, r, dx);
  }
  p->d = getD(p->ls) + getD(p->rs);
}
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]];
  }
  if (dep[u] > dep[v]) swap(u, v);
  return u;
}
long long qTree(int u) {
  if (u == R)
    return query(rt, 1, N);
  else if (lca(u, R) != u) {
    return query(rt, id[u], id[u] + size[u] - 1);
  } else {
    int p = R;
    for (int j = 20; j >= 0; j--) {
      if (dep[anc[p][j]] > dep[u]) {
        p = anc[p][j];
      }
    }
    return query(rt, 1, N) - query(rt, id[p], id[p] + size[p] - 1);
  }
}
void updTree(int u, int dx) {
  if (u == R)
    change(rt, 1, N, dx);
  else if (lca(u, R) != u) {
    change(rt, id[u], id[u] + size[u] - 1, dx);
  } else {
    int p = R;
    for (int j = 20; j >= 0; j--) {
      if (dep[anc[p][j]] > dep[u]) {
        p = anc[p][j];
      }
    }
    change(rt, 1, N, dx);
    change(rt, id[p], id[p] + size[p] - 1, -dx);
  }
}
int main() {
  scanf("%d%d", &N, &Q);
  for (int i = 1; i <= N; i++) scanf("%d", &w[i]);
  int u, v;
  for (int i = 1; i < N; i++) {
    scanf("%d%d", &u, &v);
    Adj[u].push_back(v);
    Adj[v].push_back(u);
  }
  dfs1(1);
  dfs2(1, 1);
  rt = buildT(1, N);
  int op, dx;
  int z, z1, z2, z3;
  R = 1;
  while (Q--) {
    scanf("%d", &op);
    switch (op) {
      case 1:
        scanf("%d", &u);
        R = u;
        break;
      case 2:
        scanf("%d%d%d", &u, &v, &dx);
        z1 = lca(u, R);
        z2 = lca(v, R);
        z3 = lca(u, v);
        z = z1;
        if (dep[z] < dep[z2]) z = z2;
        if (dep[z] < dep[z3]) z = z3;
        updTree(z, dx);
        break;
      case 3:
        scanf("%d", &u);
        printf("%lld\n", qTree(u));
        break;
    }
  }
  return 0;
}
