#include <bits/stdc++.h>
using namespace std;
int read() {
  char ch = getchar();
  int f = 0, x = 1;
  while (ch < '0' || ch > '9') {
    if (ch == '-') x = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    f = (f << 1) + (f << 3) + ch - '0';
    ch = getchar();
  }
  return f * x;
}
struct segtree {
  int ls;
  int rs;
  long long sum;
  long long mark;
} tree[400005];
struct node {
  int from;
  int to;
  int next;
} edge[200005];
int tot = 1, pos[100005], npos[100005], size[100005];
int cnt, n, head[200005], m, rt, tar, fa[200005], a[200005];
int anc[200005][25];
bool vis[200005];
int dep[200005];
void add(int u, int v) {
  edge[cnt].from = u;
  edge[cnt].to = v;
  edge[cnt].next = head[u];
  head[u] = cnt++;
}
void build(int p, int l, int r) {
  int mid = l + r >> 1;
  if (l == r) {
    tree[p].sum = a[npos[mid]];
    return;
  }
  tree[p].ls = ++tot;
  tree[p].rs = ++tot;
  build(tree[p].ls, l, mid);
  build(tree[p].rs, mid + 1, r);
  tree[p].sum = tree[tree[p].ls].sum + tree[tree[p].rs].sum;
}
void dfs(int x) {
  size[x] = 1;
  pos[x] = ++tar;
  npos[tar] = x;
  for (int i = head[x]; i != -1; i = edge[i].next) {
    if (fa[x] != edge[i].to) {
      fa[edge[i].to] = x;
      dfs(edge[i].to);
      size[x] += size[edge[i].to];
    }
  }
}
void dfs2(int x) {
  vis[x] = 1;
  for (int i = 1; i <= 20; i++) {
    if (dep[x] <= (1 << i)) break;
    anc[x][i] = anc[anc[x][i - 1]][i - 1];
  }
  for (int i = head[x]; i != -1; i = edge[i].next) {
    if (!anc[edge[i].to][0] && edge[i].to != rt) {
      dep[edge[i].to] = dep[x] + 1;
      anc[edge[i].to][0] = x;
      dfs2(edge[i].to);
    }
  }
}
int lca(int x, int y) {
  if (dep[x] < dep[y]) swap(x, y);
  for (int i = 20; i >= 0; i--) {
    if (dep[y] <= dep[anc[x][i]]) {
      x = anc[x][i];
    }
  }
  if (x == y) return x;
  for (int i = 20; i >= 0; i--) {
    if (anc[x][i] != anc[y][i]) {
      x = anc[x][i];
      y = anc[y][i];
    }
  }
  if (x == y) return x;
  if (!anc[x][0]) return 1;
  return anc[x][0];
}
long long query(int p, int l, int r, int x, int y) {
  int mid = l + r >> 1;
  if (l == x && r == y) return tree[p].sum;
  if (tree[p].mark) {
    tree[tree[p].ls].mark += tree[p].mark;
    tree[tree[p].rs].mark += tree[p].mark;
    tree[tree[p].ls].sum += 1LL * (mid - l + 1) * tree[p].mark;
    tree[tree[p].rs].sum += 1LL * (r - mid) * tree[p].mark;
    tree[p].mark = 0;
  }
  if (y <= mid)
    return query(tree[p].ls, l, mid, x, y);
  else if (x > mid)
    return query(tree[p].rs, mid + 1, r, x, y);
  else {
    return query(tree[p].ls, l, mid, x, mid) +
           query(tree[p].rs, mid + 1, r, mid + 1, y);
  }
}
void modify(int p, int l, int r, int x, int y, int z) {
  int mid = l + r >> 1;
  if (l == x && r == y) {
    tree[p].sum += 1LL * (r - l + 1) * z;
    tree[p].mark += z;
    return;
  }
  if (tree[p].mark) {
    tree[tree[p].ls].mark += tree[p].mark;
    tree[tree[p].rs].mark += tree[p].mark;
    tree[tree[p].ls].sum += 1LL * (mid - l + 1) * tree[p].mark;
    tree[tree[p].rs].sum += 1LL * (r - mid) * tree[p].mark;
    tree[p].mark = 0;
  }
  if (y <= mid)
    modify(tree[p].ls, l, mid, x, y, z);
  else if (x > mid)
    modify(tree[p].rs, mid + 1, r, x, y, z);
  else {
    modify(tree[p].ls, l, mid, x, mid, z);
    modify(tree[p].rs, mid + 1, r, mid + 1, y, z);
  }
  tree[p].sum = tree[tree[p].ls].sum + tree[tree[p].rs].sum;
}
int getp(int x) {
  int now = rt;
  for (int i = 20; i >= 0; i--) {
    if (dep[anc[now][i]] >= dep[x] + 1) {
      now = anc[now][i];
    }
  }
  return now;
}
int main() {
  memset(head, -1, sizeof(head));
  n = read();
  m = read();
  for (int i = 1; i <= n; i++) a[i] = read();
  for (int i = 1; i < n; i++) {
    int u = read(), v = read();
    add(u, v);
    add(v, u);
  }
  dep[1] = 1;
  rt = 1;
  dfs(1);
  dfs2(1);
  build(1, 1, n);
  for (int i = 1; i <= m; i++) {
    int op = read();
    if (op == 1) {
      rt = read();
    } else if (op == 2) {
      int x = read(), y = read(), z = read();
      x = lca(x, y) ^ lca(x, rt) ^ lca(y, rt);
      if (x == rt)
        modify(1, 1, n, 1, n, z);
      else if (lca(x, rt) == x) {
        modify(1, 1, n, 1, n, z);
        int now = getp(x);
        modify(1, 1, n, pos[now], pos[now] + size[now] - 1, -z);
      } else {
        modify(1, 1, n, pos[x], pos[x] + size[x] - 1, z);
      }
    } else if (op == 3) {
      int x = read();
      if (x == rt)
        printf("%lld\n", tree[1].sum);
      else if (lca(x, rt) == x) {
        int now = getp(x);
        printf("%lld\n", tree[1].sum - query(1, 1, n, pos[now],
                                             pos[now] + size[now] - 1));
      } else {
        printf("%lld\n", query(1, 1, n, pos[x], pos[x] + size[x] - 1));
      }
    }
  }
}
