#include <bits/stdc++.h>
using namespace std;
long long n, q, cnt = 0, rt = 1;
long long a[300005];
long long dat[2400005];
long long tag[2400005];
long long par[300005][20];
long long dep[300005];
long long L[300005];
long long R[300005];
vector<long long> edge[300005];
void read() {
  scanf("%lld%lld", &n, &q);
  for (long long i = 1; i <= n; i++) scanf("%lld", &a[i]);
  long long x, y;
  for (long long i = 1; i < n; i++) {
    scanf("%lld%lld", &x, &y);
    edge[x].push_back(y);
    edge[y].push_back(x);
  }
}
void push_down(long long k, long long len) {
  if (tag[k]) {
    dat[k * 2 + 1] += tag[k] * (len - (len >> 1));
    dat[k * 2 + 2] += tag[k] * (len >> 1);
    tag[k * 2 + 1] += tag[k];
    tag[k * 2 + 2] += tag[k];
    tag[k] = 0;
  }
}
void push_up(long long k) { dat[k] = dat[k * 2 + 1] + dat[k * 2 + 2]; }
void update(long long a, long long b, long long k, long long l, long long r,
            long long x) {
  if (a <= l && r <= b) {
    dat[k] += (r - l + 1) * x, tag[k] += x;
    return;
  }
  push_down(k, r - l + 1);
  long long mid = (l + r) >> 1;
  if (a <= mid) update(a, b, k * 2 + 1, l, mid, x);
  if (b > mid) update(a, b, k * 2 + 2, mid + 1, r, x);
  push_up(k);
}
long long query(long long a, long long b, long long k, long long l,
                long long r) {
  if (a <= l && r <= b) return dat[k];
  push_down(k, r - l + 1);
  long long mid = (l + r) >> 1, ans = 0;
  if (a <= mid) ans += query(a, b, k * 2 + 1, l, mid);
  if (b > mid) ans += query(a, b, k * 2 + 2, mid + 1, r);
  return ans;
}
void dfs1(long long x, long long d, long long p) {
  par[x][0] = p, dep[x] = d, L[x] = ++cnt;
  for (long long k = 0; k + 1 < 20; k++) {
    if (par[x][k]) par[x][k + 1] = par[par[x][k]][k];
  }
  for (long long i = 0; i < edge[x].size(); i++) {
    long long t = edge[x][i];
    if (t != p) dfs1(t, d + 1, x);
  }
  R[x] = cnt;
}
long long lca(long long a, long long b) {
  if (dep[a] < dep[b]) swap(a, b);
  for (long long k = 0; k < 20 && dep[a] != dep[b]; k++) {
    if (((dep[a] - dep[b]) >> k) & 1) a = par[a][k];
  }
  if (a == b) return a;
  for (long long k = 20 - 1; k >= 0; k--) {
    if (par[a][k] != par[b][k]) {
      a = par[a][k], b = par[b][k];
    }
  }
  return par[a][0];
}
long long get_son(long long x) {
  long long a = rt;
  for (long long k = 0; k < 20 && dep[x] + 1 != dep[a]; k++) {
    if (((dep[rt] - dep[x] - 1) >> k) & 1) a = par[a][k];
  }
  return a;
}
inline bool in_tree(long long s, long long p) {
  return L[p] <= L[s] && L[s] <= R[p];
}
inline bool in_path(long long s) { return lca(s, rt) == s; }
long long get_lca(long long a, long long b) {
  bool fa = in_tree(a, rt), fb = in_tree(b, rt);
  if (fa & fb) return lca(a, b);
  if (fa ^ fb) return rt;
  long long p = lca(a, b);
  if (!in_path(p)) return p;
  long long la = lca(rt, a), lb = lca(rt, b);
  return dep[la] > dep[lb] ? la : lb;
}
void add(long long x, long long v) { update(L[x], R[x], 0, 1, n, v); }
void add_tree(long long x, long long v) {
  if (x == rt)
    add(1, v);
  else if (!in_tree(rt, x))
    add(x, v);
  else
    add(1, v), add(get_son(x), -v);
}
void add_sub(long long x, long long y, long long z) {
  long long p = get_lca(x, y);
  add_tree(p, z);
}
long long get_sum(long long x) { return query(L[x], R[x], 0, 1, n); }
long long query_sub(long long x) {
  long long ans = 0;
  if (rt == x)
    ans += get_sum(1);
  else if (!in_tree(rt, x))
    ans += get_sum(x);
  else
    ans += get_sum(1), ans -= get_sum(get_son(x));
  return ans;
}
void init() {
  dfs1(1, 0, 0);
  for (long long i = 1; i <= n; i++) update(L[i], L[i], 0, 1, n, a[i]);
}
void work() {
  init();
  long long opt, x, y, z;
  while (q--) {
    scanf("%lld%lld", &opt, &x);
    if (opt == 1) rt = x;
    if (opt == 2) scanf("%lld%lld", &y, &z), add_sub(x, y, z);
    if (opt == 3) printf("%lld\n", query_sub(x));
  }
}
signed main() {
  read();
  work();
}
