#include <bits/stdc++.h>
using namespace std;
vector<long long> adList[100000];
long long val[100000];
long long depth[100000];
long long ancestor[100000][32];
vector<long long> eulerTour;
vector<long long> dfsIndices;
vector<long long> dfsValues;
long long subtreeStart[100000];
long long subtreeFinish[100000];
long long segTreeAdd[400010];
pair<long long, long long> segTreeMin[1000000];
long long lazy[400010];
long long first[100000];
pair<long long, long long> constructSTmin(long long index, long long low,
                                          long long high) {
  if (low == high) {
    segTreeMin[index] = {depth[eulerTour[low]], low};
    return segTreeMin[index];
  } else {
    long long mid = low + (high - low) / 2;
    pair<long long, long long> p1 = constructSTmin(2 * index + 1, low, mid);
    pair<long long, long long> p2 =
        constructSTmin(2 * index + 2, mid + 1, high);
    if (p1.first <= p2.first)
      segTreeMin[index] = p1;
    else
      segTreeMin[index] = p2;
    return segTreeMin[index];
  }
}
long long constructSTadd(long long index, long long low, long long high) {
  if (low == high) {
    segTreeAdd[index] = dfsValues[low];
    return segTreeAdd[index];
  } else {
    long long mid = low + (high - low) / 2;
    segTreeAdd[index] = constructSTadd(2 * index + 1, low, mid) +
                        constructSTadd(2 * index + 2, mid + 1, high);
    return segTreeAdd[index];
  }
}
pair<long long, long long> rmq(long long index, long long qlow, long long qhigh,
                               long long slow, long long shigh) {
  if (slow > qhigh || shigh < qlow)
    return {INT_MAX, -1};
  else {
    if (slow >= qlow && shigh <= qhigh)
      return segTreeMin[index];
    else {
      long long mid = slow + (shigh - slow) / 2;
      pair<long long, long long> p1 =
          rmq(2 * index + 1, qlow, qhigh, slow, mid);
      pair<long long, long long> p2 =
          rmq(2 * index + 2, qlow, qhigh, mid + 1, shigh);
      if (p1.first <= p2.first)
        return p1;
      else
        return p2;
    }
  }
}
long long updateSTadd(long long index, long long qlow, long long qhigh,
                      long long slow, long long shigh, long long x) {
  if (lazy[index] != 0) {
    if (slow != shigh) {
      lazy[2 * index + 1] += lazy[index];
      lazy[2 * index + 2] += lazy[index];
    }
    segTreeAdd[index] += (shigh - slow + 1) * lazy[index];
    lazy[index] = 0;
  }
  if (slow > qhigh || shigh < qlow)
    return 0;
  else {
    if (slow >= qlow && shigh <= qhigh) {
      segTreeAdd[index] += (shigh - slow + 1) * x;
      if (slow != shigh) {
        lazy[2 * index + 1] += x;
        lazy[2 * index + 2] += x;
      }
      return (shigh - slow + 1) * x;
    } else {
      long long mid = slow + (shigh - slow) / 2;
      long long upd =
          updateSTadd(2 * index + 1, qlow, qhigh, slow, mid, x) +
          updateSTadd(2 * index + 2, qlow, qhigh, mid + 1, shigh, x);
      segTreeAdd[index] += upd;
      return upd;
    }
  }
}
long long getSTadd(long long index, long long qlow, long long qhigh,
                   long long slow, long long shigh) {
  if (lazy[index] != 0) {
    if (slow != shigh) {
      lazy[2 * index + 1] += lazy[index];
      lazy[2 * index + 2] += lazy[index];
    }
    segTreeAdd[index] += (shigh - slow + 1) * lazy[index];
    lazy[index] = 0;
  }
  if (slow > qhigh || shigh < qlow)
    return 0;
  else {
    if (slow >= qlow && shigh <= qhigh)
      return segTreeAdd[index];
    else {
      long long mid = slow + (shigh - slow) / 2;
      return getSTadd(2 * index + 1, qlow, qhigh, slow, mid) +
             getSTadd(2 * index + 2, qlow, qhigh, mid + 1, shigh);
    }
  }
}
long long getNthAncestor(long long v, long long h) {
  if (h == 0) return v;
  for (long long i = 30; i >= 0; i--) {
    if ((1 << i) <= (h)) {
      v = ancestor[v][i];
      h = h - (1 << i);
    }
  }
  return v;
}
void dfs(long long start, long long prnt, long long& dfsTime, long long dep,
         long long& p) {
  if (dep != 0) {
    long long acs = 0;
    long long depcopy = dep;
    while (depcopy != 0) {
      depcopy /= 2;
      acs++;
    }
    for (long long j = 0; j < acs; j++) {
      if (j == 0) {
        ancestor[start][j] = prnt;
      } else
        ancestor[start][j] = ancestor[ancestor[start][j - 1]][j - 1];
    }
  }
  subtreeStart[start] = dfsTime;
  eulerTour.push_back(start);
  first[start] = p;
  p++;
  dfsIndices.push_back(start);
  dfsTime++;
  depth[start] = dep;
  for (long long i = 0; i < adList[start].size(); i++) {
    long long node = adList[start][i];
    if (node != prnt) {
      dfs(node, start, dfsTime, dep + 1, p);
      eulerTour.push_back(start);
      p++;
    }
  }
  subtreeFinish[start] = dfsTime;
}
long long findLCA(long long u, long long v) {
  if (first[u] <= first[v])
    return eulerTour[(
        (rmq(0, first[u], first[v], 0, eulerTour.size() - 1)).second)];
  else
    return eulerTour[(
        (rmq(0, first[v], first[u], 0, eulerTour.size() - 1)).second)];
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  for (long long i = 0; i < 400010; i++) {
    segTreeAdd[i] = 0;
    lazy[i] = 0;
  }
  long long n, q;
  cin >> n >> q;
  for (long long i = 0; i < n; i++) {
    subtreeFinish[i] = subtreeStart[i] = -1;
    adList[i].clear();
    depth[i] = -1;
  }
  for (long long i = 0; i < n; i++) {
    cin >> val[i];
  }
  for (long long i = 0; i < n - 1; i++) {
    long long u, v;
    cin >> u >> v;
    u--, v--;
    adList[u].push_back(v);
    adList[v].push_back(u);
  }
  long long dfsTime = 0;
  long long p = 0;
  dfs(0, -1, dfsTime, 0, p);
  for (long long i = 0; i < n; i++) {
    dfsValues.push_back(val[dfsIndices[i]]);
  }
  constructSTmin(0, 0, p - 1);
  constructSTadd(0, 0, n - 1);
  long long root = 0;
  for (long long _ = 0; _ < q; _++) {
    long long type;
    cin >> type;
    if (type == 1) {
      long long r;
      cin >> r;
      root = r - 1;
    } else if (type == 2) {
      long long u, v, x;
      cin >> u >> v >> x;
      u--, v--;
      long long lca = findLCA(u, v);
      long long lca1 = findLCA(u, root);
      long long lca2 = findLCA(v, root);
      long long finalLCA;
      if (depth[lca] >= depth[lca1] && depth[lca] >= depth[lca2]) {
        finalLCA = lca;
      } else if (depth[lca1] >= depth[lca] && depth[lca1] >= depth[lca2]) {
        finalLCA = lca1;
      } else {
        finalLCA = lca2;
      }
      if (finalLCA == root) {
        updateSTadd(0, 0, n - 1, 0, n - 1, x);
      } else if (subtreeStart[finalLCA] >= subtreeStart[root] &&
                 subtreeStart[finalLCA] < subtreeFinish[root]) {
        updateSTadd(0, subtreeStart[finalLCA], subtreeFinish[finalLCA] - 1, 0,
                    n - 1, x);
      } else if (!(subtreeStart[root] >= subtreeStart[finalLCA] &&
                   subtreeStart[root] < subtreeFinish[finalLCA])) {
        updateSTadd(0, subtreeStart[finalLCA], subtreeFinish[finalLCA] - 1, 0,
                    n - 1, x);
      } else {
        updateSTadd(0, 0, n - 1, 0, n - 1, x);
        long long diff = depth[root] - depth[finalLCA] - 1;
        long long node = getNthAncestor(root, diff);
        updateSTadd(0, subtreeStart[node], subtreeFinish[node] - 1, 0, n - 1,
                    -x);
      }
    } else {
      long long v;
      cin >> v;
      v--;
      if (v == root) {
        cout << getSTadd(0, 0, n - 1, 0, n - 1) << endl;
      } else if (subtreeStart[v] >= subtreeStart[root] &&
                 subtreeStart[v] < subtreeFinish[root]) {
        cout << getSTadd(0, subtreeStart[v], subtreeFinish[v] - 1, 0, n - 1)
             << endl;
      } else if (!(subtreeStart[root] >= subtreeStart[v] &&
                   subtreeStart[root] < subtreeFinish[v])) {
        cout << getSTadd(0, subtreeStart[v], subtreeFinish[v] - 1, 0, n - 1)
             << endl;
      } else {
        long long ans = 0;
        ans = getSTadd(0, 0, n - 1, 0, n - 1);
        long long diff = depth[root] - depth[v] - 1;
        long long node = getNthAncestor(root, diff);
        ans -=
            getSTadd(0, subtreeStart[node], subtreeFinish[node] - 1, 0, n - 1);
        cout << ans << endl;
      }
    }
  }
}
