#include <bits/stdc++.h>
using namespace std;
long long gcd(long long n1, long long n2) {
  if (!n1) return n2;
  if (!n2) return n1;
  if (n1 % n2 == 0) return n2;
  return gcd(n2, n1 % n2);
}
long long powmod(long long base, long long exponent) {
  base %= 1000000007;
  long long ans = 1;
  while (exponent) {
    if (exponent & 1) ans = (ans * base) % 1000000007;
    base = (base * base) % 1000000007;
    exponent /= 2;
  }
  ans %= 1000000007;
  return ans;
}
vector<int> adj[1000100 + 1];
vector<int> child[1000100 + 1];
bool visited[1000100 + 1];
int in[1000100 + 1];
int out[1000100 + 1];
int arr[1000100 + 1];
int level[1000100 + 1];
int sparse[1000100 + 1][20 + 1];
int timer = 0;
bool cmp(int a, int b) { return (in[a] < in[b]); }
void dfs(int node, int lv, int parent) {
  in[node] = (++timer);
  level[node] = lv;
  sparse[node][0] = parent;
  visited[node] = true;
  for (int i = 0; i < adj[node].size(); i++)
    if (!visited[adj[node][i]]) {
      child[node].push_back(adj[node][i]);
      dfs(adj[node][i], lv + 1, node);
    }
  sort(child[node].begin(), child[node].end(), cmp);
  out[node] = (timer);
}
bool isancestor(int u, int v) {
  return ((in[u] >= in[v]) && (out[u] <= out[v]));
}
long long segtree[8 * 1000100 + 1];
long long lazy[8 * 1000100 + 1];
long long query(int node, int i, int j, int l, int r) {
  if (lazy[node] != 0) {
    segtree[node] += lazy[node] * (j - i + 1);
    lazy[2 * node] += lazy[node];
    lazy[2 * node + 1] += lazy[node];
    lazy[node] = 0;
  }
  if (i > j || i > r || j < l || l > r) return 0;
  if (i >= l && j <= r) return segtree[node];
  int mid = (i + j) >> 1;
  return (query(2 * node, i, mid, l, r) +
          query(2 * node + 1, mid + 1, j, l, r));
}
void update(int node, int i, int j, int l, int r, long long val) {
  if (lazy[node] != 0) {
    segtree[node] += lazy[node] * (j - i + 1);
    lazy[2 * node] += lazy[node];
    lazy[2 * node + 1] += lazy[node];
    lazy[node] = 0;
  }
  if (i > j || i > r || j < l || l > r) return;
  if (i >= l && j <= r) {
    segtree[node] += val * (j - i + 1);
    lazy[2 * node] += val;
    lazy[2 * node + 1] += val;
    return;
  }
  int mid = (i + j) >> 1;
  update(2 * node, i, mid, l, r, val);
  update(2 * node + 1, mid + 1, j, l, r, val);
  segtree[node] = segtree[2 * node] + segtree[2 * node + 1];
}
int fuck(int kiska, int root) {
  int l, r, mid, sz = child[kiska].size();
  l = 0, r = sz - 1;
  while (r - l > 1) {
    mid = (l + r) >> 1;
    if (in[child[kiska][mid]] > in[root])
      r = mid;
    else
      l = mid;
  }
  while (in[child[kiska][r]] > in[root]) r--;
  return child[kiska][r];
}
int lca(int a, int b) {
  if (level[a] > level[b]) swap(a, b);
  int temp = (level[b] - level[a]);
  for (int j = 20; j >= 0; j--)
    if ((temp >> j) & 1) b = sparse[b][j];
  if (a == b) return a;
  for (int j = 20; j >= 0; j--)
    if (sparse[a][j] != sparse[b][j]) {
      a = sparse[a][j];
      b = sparse[b][j];
    }
  return sparse[a][0];
}
int main() {
  int n, q, a, b, x, i, j, k, Q;
  scanf("%d", &n);
  scanf("%d", &q);
  for (i = 1; i <= n; i++) scanf("%d", &arr[i]);
  for (i = 1; i < n; i++) {
    scanf("%d", &a);
    scanf("%d", &b);
    adj[a].push_back(b);
    adj[b].push_back(a);
  }
  dfs(1, 1, 1);
  for (j = 1; j <= 20; j++)
    for (i = 1; i <= n; i++) sparse[i][j] = sparse[sparse[i][j - 1]][j - 1];
  for (i = 1; i <= n; i++) update(1, 1, n, in[i], in[i], arr[i]);
  int root = 1;
  while (q--) {
    scanf("%d", &Q);
    if (Q == 1) {
      scanf("%d", &root);
    }
    if (Q == 2) {
      scanf("%d", &a);
      scanf("%d", &b);
      scanf("%d", &x);
      int newlca;
      newlca = (lca(a, b) ^ lca(a, root) ^ lca(b, root));
      if (newlca == root) {
        update(1, 1, n, 1, n, x);
      } else {
        if (isancestor(newlca, root)) {
          update(1, 1, n, in[newlca], out[newlca], x);
        } else {
          if (!isancestor(root, newlca)) {
            update(1, 1, n, in[newlca], out[newlca], x);
          } else {
            update(1, 1, n, 1, n, x);
            int childcontainingnewroot = fuck(newlca, root);
            update(1, 1, n, in[childcontainingnewroot],
                   out[childcontainingnewroot], -x);
          }
        }
      }
    }
    if (Q == 3) {
      scanf("%d", &a);
      if (a == root) {
        printf("%lld\n", query(1, 1, n, 1, n));
      } else {
        if (isancestor(a, root)) {
          printf("%lld\n", query(1, 1, n, in[a], out[a]));
        } else {
          if (!isancestor(root, a)) {
            printf("%lld\n", query(1, 1, n, in[a], out[a]));
          } else {
            long long answer = query(1, 1, n, 1, n);
            int childcontainingnewroot = fuck(a, root);
            answer -= query(1, 1, n, in[childcontainingnewroot],
                            out[childcontainingnewroot]);
            printf("%lld\n", answer);
          }
        }
      }
    }
  }
  return 0;
}
