#include <bits/stdc++.h>
int II() {
  int n;
  scanf("%d", &n);
  return n;
}
void II(int n) { printf("%d", n); }
void IIn(int n) { printf("%d\n", n); }
void IIb(int n) { printf("%d ", n); }
long long int LL() {
  long long int n;
  scanf("%lld", &n);
  return n;
}
void LL(long long int n) { printf("%lld", n); }
void LLn(long long int n) { printf("%lld\n", n); }
void LLb(long long int n) { printf("%lld ", n); }
char CC() { return getchar(); }
char CCa() {
  char c = getchar();
  while (c <= 32) c = getchar();
  return c;
}
void CC(char c) { putchar(c); }
void CCn(char c) {
  putchar(c);
  putchar(10);
}
void CCb(char c) {
  putchar(c);
  putchar(32);
}
void CCn() { putchar(10); }
void CCb() { putchar(32); }
void SS(char *s) { scanf("%s", s); }
void SSb(const char *s) { printf("%s ", s); }
void SSn(const char *s) { printf("%s\n", s); }
float FF() {
  float n;
  scanf("%f", &n);
  return n;
}
void FF(float n) { printf("%f", n); }
void FFn(float n) { printf("%f\n", n); }
void FFb(float n) { printf("%f ", n); }
void FF(double n, int prec) { std::cout << std::setprecision(prec) << n; }
void FFn(double n, int prec) {
  std::cout << std::setprecision(prec) << n;
  putchar(10);
}
void FFb(double n, int prec) {
  std::cout << std::setprecision(prec) << n;
  putchar(32);
}
constexpr int MAXN = 100000, LOGMAXN = 20;
struct node {
  long long int sum, lazy;
  int l, r;
  node *left, *right;
  void build(int pl, int pr);
  void full_add(long long int x);
  void propage();
  long long int query(int s, int e);
  void add(int s, int e, long long int x);
};
node mem[MAXN * 3];
node *get_mem = mem;
std::vector<int> adj[MAXN];
int initial_weights[MAXN], dfs_pos[MAXN], rev_dfs_pos[MAXN], dfs_end[MAXN],
    depth[MAXN], father[LOGMAXN][MAXN];
int _t = 0;
void node::build(int pl, int pr) {
  l = pl;
  r = pr;
  lazy = 0;
  if (l == r) {
    sum = initial_weights[rev_dfs_pos[l]];
    left = right = NULL;
  } else {
    left = get_mem++;
    right = get_mem++;
    int m = (l + r) / 2;
    left->build(l, m);
    right->build(m + 1, r);
    sum = left->sum + right->sum;
  }
}
void node::full_add(long long int x) {
  lazy += x;
  sum += x * (r - l + 1);
}
void node::propage() {
  left->full_add(lazy);
  right->full_add(lazy);
  lazy = 0;
}
long long int node::query(int s, int e) {
  if (e < l || s > r) return 0;
  if (s <= l && r <= e) return sum;
  propage();
  return left->query(s, e) + right->query(s, e);
}
void node::add(int s, int e, long long int x) {
  if (e < l || s > r) return;
  if (s <= l && r <= e) return full_add(x);
  propage();
  left->add(s, e, x);
  right->add(s, e, x);
  sum = left->sum + right->sum;
}
void dfs(int u, int f, int d) {
  rev_dfs_pos[_t] = u;
  dfs_pos[u] = _t++;
  depth[u] = d;
  father[0][u] = f;
  for (int v : adj[u])
    if (v != f) dfs(v, u, d + 1);
  dfs_end[u] = _t - 1;
}
int up_path(int u, int k) {
  for (int l = 0; l < LOGMAXN; l++, k >>= 1)
    if (k & 1) u = father[l][u];
  return u;
}
int lca(int x, int y) {
  if (depth[x] > depth[y]) std::swap(x, y);
  y = up_path(y, depth[y] - depth[x]);
  if (y == x) return x;
  for (int l = LOGMAXN - 1; l >= 0; l--) {
    int xp = father[l][x], yp = father[l][y];
    if (xp != yp) {
      x = xp;
      y = yp;
    }
  }
  return father[0][x];
}
int main() {
  int N = II(), Q = II();
  for (int i = 0; i < N; i++) initial_weights[i] = II();
  for (int M = N - 1; M--;) {
    int u = II() - 1, v = II() - 1;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  dfs(0, -1, 0);
  father[0][0] = 0;
  for (int l = 1; l < LOGMAXN; l++)
    for (int i = 0; i < N; i++) father[l][i] = father[l - 1][father[l - 1][i]];
  node tree;
  tree.build(0, N - 1);
  int root = 0, root_pos = 0, root_end = N - 1;
  while (Q--) {
    int t = II();
    if (t == 1) {
      root = II() - 1;
      root_pos = dfs_pos[root];
      root_end = dfs_end[root];
    } else if (t == 2) {
      int u = II() - 1, v = II() - 1, x = II();
      int uv = lca(u, v), ur = lca(u, root), vr = lca(v, root);
      if (vr == ur && ur == root) {
        if (uv == root)
          tree.add(0, N - 1, x);
        else
          tree.add(dfs_pos[uv], dfs_end[uv], x);
      } else if (ur == root || vr == root)
        tree.add(0, N - 1, x);
      else if (vr == ur && uv != vr)
        tree.add(dfs_pos[uv], dfs_end[uv], x);
      else {
        if (uv != ur) std::swap(ur, vr);
        if (uv != ur) throw;
        int k = up_path(root, depth[root] - depth[vr] - 1);
        tree.add(0, N - 1, x);
        tree.add(dfs_pos[k], dfs_end[k], -x);
      }
    } else {
      int u = II() - 1;
      if (u == root)
        LLn(tree.query(0, N - 1));
      else if (dfs_pos[u] > root_pos && dfs_pos[u] <= root_end)
        LLn(tree.query(dfs_pos[u], dfs_end[u]));
      else if (depth[u] < depth[root] &&
               up_path(root, depth[root] - depth[u]) == u) {
        int k = up_path(root, depth[root] - depth[u] - 1);
        LLn(tree.query(0, N - 1) - tree.query(dfs_pos[k], dfs_end[k]));
      } else
        LLn(tree.query(dfs_pos[u], dfs_end[u]));
    }
  }
}
