#include <bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x) {
  x = 0;
  char ch = getchar();
  bool f = false;
  while (!isdigit(ch)) f |= ch == '-', ch = getchar();
  while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
  x = f ? -x : x;
}
template <typename T>
inline void print(T x) {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9) print(x / 10);
  putchar(x % 10 ^ 48);
}
const int N = 2e5 + 5;
int n, m, root;
int head[N], nex[N], to[N], idx, val[N];
int dep[N], siz[N], son[N], fa[N], dfn[N], top[N], rev[N], tot;
void Add(int u, int v) {
  nex[++idx] = head[u];
  to[idx] = v;
  head[u] = idx;
  return;
}
void Dfs1(int x, int f) {
  siz[x] = 1, fa[x] = f, dep[x] = dep[f] + 1;
  for (int i = head[x]; i; i = nex[i]) {
    int y = to[i];
    if (y == f) continue;
    Dfs1(y, x);
    siz[x] += siz[y];
    if (siz[y] > siz[son[x]]) son[x] = y;
  }
  return;
}
void Dfs2(int x) {
  if (x == son[fa[x]])
    top[x] = top[fa[x]];
  else
    top[x] = x;
  dfn[x] = ++tot;
  rev[tot] = x;
  if (son[x]) Dfs2(son[x]);
  for (int i = head[x]; i; i = nex[i]) {
    int y = to[i];
    if (y == fa[x] || y == son[x]) continue;
    Dfs2(y);
  }
  return;
}
long long sum[N << 2], add[N << 2];
void Pushup(int x) {
  sum[x] = sum[x << 1] + sum[x << 1 | 1];
  return;
}
void PushDown(int x, int l, int r) {
  if (!add[x]) return;
  int mid = l + r >> 1;
  sum[x << 1] += add[x] * (mid - l + 1);
  sum[x << 1 | 1] += add[x] * (r - mid);
  add[x << 1] += add[x], add[x << 1 | 1] += add[x];
  add[x] = 0;
  return;
}
void Build(int x, int l, int r) {
  if (l == r) {
    sum[x] = val[rev[l]];
    return;
  }
  int mid = l + r >> 1;
  Build(x << 1, l, mid), Build(x << 1 | 1, mid + 1, r);
  Pushup(x);
  return;
}
void Modify(int x, int l, int r, int ql, int qr, int k) {
  if (ql <= l && qr >= r) {
    sum[x] += 1ll * (r - l + 1) * k;
    add[x] += k;
    return;
  }
  PushDown(x, l, r);
  int mid = l + r >> 1;
  if (ql <= mid) Modify(x << 1, l, mid, ql, qr, k);
  if (qr > mid) Modify(x << 1 | 1, mid + 1, r, ql, qr, k);
  Pushup(x);
  return;
}
long long Query(int x, int l, int r, int ql, int qr) {
  if (ql <= l && qr >= r) return sum[x];
  PushDown(x, l, r);
  int mid = l + r >> 1;
  long long res = 0;
  if (ql <= mid) res += Query(x << 1, l, mid, ql, qr);
  if (qr > mid) res += Query(x << 1 | 1, mid + 1, r, ql, qr);
  return res;
}
void RoadModify(int x, int y, int k) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    Modify(1, 1, n, dfn[top[x]], dfn[x], k);
    x = fa[top[x]];
  }
  if (dep[x] < dep[y]) swap(x, y);
  Modify(1, 1, n, dfn[y], dfn[x], k);
  return;
}
long long RoadQuery(int x, int y) {
  long long res = 0;
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    res += Query(1, 1, n, dfn[top[x]], dfn[x]);
    x = fa[top[x]];
  }
  if (dep[x] < dep[y]) swap(x, y);
  res += Query(1, 1, n, dfn[y], dfn[x]);
  return res;
}
int QueryLCA(int x, int y) {
  while (top[x] != top[y]) {
    if (dep[top[x]] < dep[top[y]]) swap(x, y);
    x = fa[top[x]];
  }
  if (dep[x] < dep[y]) swap(x, y);
  return y;
}
int Find(int x, int 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]];
  }
  if (dep[x] > dep[y]) swap(x, y);
  return son[x];
}
void TreeModify(int x, int k) {
  if (root == x) {
    Modify(1, 1, n, 1, n, k);
    return;
  }
  int lca = QueryLCA(x, root);
  if (lca != x) {
    Modify(1, 1, n, dfn[x], dfn[x] + siz[x] - 1, k);
    return;
  }
  int id = Find(x, root);
  Modify(1, 1, n, 1, n, k), Modify(1, 1, n, dfn[id], dfn[id] + siz[id] - 1, -k);
  return;
}
long long TreeQuery(int x) {
  if (root == x) {
    return Query(1, 1, n, 1, n);
  }
  int lca = QueryLCA(x, root);
  if (lca != x) {
    return Query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1);
  }
  int id = Find(x, root);
  return Query(1, 1, n, 1, n) - Query(1, 1, n, dfn[id], dfn[id] + siz[id] - 1);
}
int LCA(int x, int y) {
  if (dep[x] > dep[y]) x ^= y ^= x ^= y;
  if (QueryLCA(x, y) == x) {
    if (dfn[root] >= dfn[y] && dfn[root] <= dfn[y] + siz[y] - 1) return y;
    if (QueryLCA(x, root) == x) return QueryLCA(y, root);
    return x;
  }
  if (dfn[root] >= dfn[x] && dfn[root] <= dfn[x] + siz[x] - 1) return x;
  if (dfn[root] >= dfn[y] && dfn[root] <= dfn[y] + siz[y] - 1) return y;
  if ((QueryLCA(x, root) == root && QueryLCA(x, y) == QueryLCA(y, root)) ||
      (QueryLCA(y, root) == root && QueryLCA(x, y) == QueryLCA(x, root)))
    return root;
  if (QueryLCA(x, root) == QueryLCA(y, root)) return QueryLCA(x, y);
  if (QueryLCA(x, y) != QueryLCA(x, root)) return QueryLCA(x, root);
  return QueryLCA(y, root);
}
int main() {
  read(n), read(m);
  for (int i = 1; i <= n; i++) read(val[i]);
  for (int i = 1; i < n; i++) {
    int u, v;
    read(u), read(v);
    Add(u, v), Add(v, u);
  }
  root = 1;
  Dfs1(1, 0);
  Dfs2(1);
  Build(1, 1, n);
  while (m--) {
    int op, x, y, w;
    read(op);
    if (op == 1) {
      read(x);
      root = x;
    } else if (op == 2) {
      read(x), read(y), read(w);
      int lca = LCA(x, y);
      TreeModify(lca, w);
    } else if (op == 3) {
      read(x);
      print(TreeQuery(x)), putchar('\n');
    }
  }
  return 0;
}
