#include <bits/stdc++.h>
template <typename T>
inline void read(T &x) {
  x = 0;
  char s = (char)getchar();
  bool f = false;
  while (!(s >= '0' && s <= '9')) {
    if (s == '-') f = true;
    s = (char)getchar();
  }
  while (s >= '0' && s <= '9') {
    x = (x << 1) + (x << 3) + s - '0';
    s = (char)getchar();
  }
  if (f) x = (~x) + 1;
}
template <typename T, typename... T1>
inline void read(T &x, T1 &...x1) {
  read(x);
  read(x1...);
}
template <typename T>
inline void clear(T *array, int l, int r, int val) {
  memset(&array[l], val, sizeof(T) * (r - l + 1));
}
using namespace std;
const int N = 3e5 + 5;
int n, m, a[N];
struct Tree_array {
  long long c[2][N];
  inline void update(int pos, int val) {
    for (int i = pos; i <= n; i += ((i) & (-(i)))) {
      c[0][i] += val;
      c[1][i] += 1ll * val * pos;
    }
  }
  inline void update(int l, int r, int val) {
    update(l, val);
    update(r + 1, -val);
  }
  inline long long query(int pos) {
    long long res = 0;
    for (register int i = pos; i; i -= ((i) & (-(i))))
      res += c[0][i] * (pos + 1) - c[1][i];
    return res;
  }
  inline long long query(int l, int r) { return query(r) - query(l - 1); }
} t;
struct Edge {
  int next, to;
} edge[N * 2];
int head[N], num_edge;
inline void add_edge(int from, int to) {
  edge[++num_edge].next = head[from];
  edge[num_edge].to = to;
  head[from] = num_edge;
}
int dfn[N], dfstime;
int size[N];
int fa[N][25];
int dep[N];
inline void dfs(int u, int _fa) {
  dfn[u] = ++dfstime;
  size[u] = 1;
  dep[u] = dep[_fa] + 1;
  fa[u][0] = _fa;
  for (int i = 0; i < 20; ++i) fa[u][i + 1] = fa[fa[u][i]][i];
  for (int i = head[u]; i; i = edge[i].next) {
    int &v = edge[i].to;
    if (v == _fa) continue;
    dfs(v, u);
    size[u] += size[v];
  }
}
inline int getlca(int u, int v) {
  if (dep[u] < dep[v]) swap(u, v);
  for (int i = 20; i >= 0; --i)
    if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
  if (u == v) return u;
  for (int i = 20; i >= 0; --i)
    if (fa[u][i] != fa[v][i]) {
      u = fa[u][i];
      v = fa[v][i];
    }
  return fa[u][0];
}
inline int jump(int u, int len) {
  for (int i = 20; i >= 0; --i)
    if ((len >> i) & 1) u = fa[u][i];
  return u;
}
inline int getlca(int u, int v, int r) {
  int uv = getlca(u, v), ur = getlca(u, r), vr = getlca(v, r);
  int ans = uv;
  if (dep[ans] < dep[ur]) ans = ur;
  if (dep[ans] < dep[vr]) ans = vr;
  return ans;
}
inline void update(int u, int r, int val) {
  if (u == r)
    t.update(1, n, val);
  else if (dfn[u] <= dfn[r] && dfn[r] <= dfn[u] + size[u] - 1) {
    t.update(1, n, val);
    int v = jump(r, dep[r] - dep[u] - 1);
    t.update(dfn[v], dfn[v] + size[v] - 1, -val);
  } else
    t.update(dfn[u], dfn[u] + size[u] - 1, val);
}
inline long long query(int u, int r) {
  if (u == r)
    return t.query(1, n);
  else if (dfn[u] <= dfn[r] && dfn[r] <= dfn[u] + size[u] - 1) {
    long long ans = t.query(1, n);
    int v = jump(r, dep[r] - dep[u] - 1);
    ans -= t.query(dfn[v], dfn[v] + size[v] - 1);
    return ans;
  } else
    return t.query(dfn[u], dfn[u] + size[u] - 1);
}
signed main() {
  read(n, m);
  for (int i = 1; i <= n; ++i) read(a[i]);
  for (int i = 1; i < n; ++i) {
    int u, v;
    read(u, v);
    add_edge(u, v);
    add_edge(v, u);
  }
  dfs(1, 0);
  for (int i = 1; i <= n; ++i) t.update(dfn[i], dfn[i], a[i]);
  int root = 1;
  for (int i = 1; i <= m; ++i) {
    int opt;
    read(opt);
    if (opt == 1)
      read(root);
    else if (opt == 2) {
      int u, v, w;
      read(u, v, w);
      update(getlca(u, v, root), root, w);
    } else if (opt == 3) {
      int u;
      read(u);
      printf("%lld\n", query(u, root));
    }
  }
  return 0;
}
