#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e5 + 9;
int n, dfsCnt, depth[MAX], spt[MAX][20], lg2[MAX], in[MAX], out[MAX],
    euler[MAX];
long long sum[MAX];
vector<int> adj[MAX];
class LazySegmentTree {
 public:
  LazySegmentTree(int sz) : n(sz) {
    tree.resize(n << 2);
    lazy.resize(n << 2);
    build(1, n, 1);
  }
  void add(int L, int R, int value) { add(1, n, 1, L, R, value); }
  long long getSum(int L, int R) { return getSum(1, n, 1, L, R); }

 private:
  void build(int low, int high, int pos) {
    if (low == high) {
      tree[pos] = sum[euler[low]];
      return;
    }
    int mid = (low + high) >> 1;
    build(low, mid, pos << 1);
    build(mid + 1, high, pos << 1 | 1);
    tree[pos] = tree[pos << 1] + tree[pos << 1 | 1];
  }
  void push(int low, int high, int pos) {
    tree[pos] += 1LL * (high - low + 1) * lazy[pos];
    if (low != high) {
      lazy[pos << 1] += lazy[pos];
      lazy[pos << 1 | 1] += lazy[pos];
    }
    lazy[pos] = 0;
  }
  void add(int low, int high, int pos, int L, int R, int value) {
    push(low, high, pos);
    if (L > high || R < low) {
      return;
    }
    if (L <= low && R >= high) {
      lazy[pos] += value;
      push(low, high, pos);
      return;
    }
    int mid = (low + high >> 1);
    add(low, mid, pos << 1, L, R, value);
    add(mid + 1, high, pos << 1 | 1, L, R, value);
    tree[pos] = tree[pos << 1] + tree[pos << 1 | 1];
  }
  long long getSum(int low, int high, int pos, int L, int R) {
    push(low, high, pos);
    if (L > high || R < low) {
      return 0;
    }
    if (L <= low & R >= high) {
      return tree[pos];
    }
    int mid = (low + high) >> 1;
    return getSum(low, mid, pos << 1, L, R) +
           getSum(mid + 1, high, pos << 1 | 1, L, R);
  }
  int n;
  vector<long long> tree;
  vector<long long> lazy;
};
void BuildLg2() {
  for (int i = 2; i < MAX; ++i) {
    lg2[i] = lg2[i >> 1] + 1;
  }
}
void Dfs(int currentNode) {
  in[currentNode] = ++dfsCnt;
  euler[dfsCnt] = currentNode;
  for (int child : adj[currentNode]) {
    if (child != spt[currentNode][0]) {
      depth[child] = depth[currentNode] + 1;
      spt[child][0] = currentNode;
      for (int j = 1; (1 << j) <= n; ++j) {
        if (spt[spt[child][j - 1]][j - 1]) {
          spt[child][j] = spt[spt[child][j - 1]][j - 1];
        } else {
          break;
        }
      }
      Dfs(child);
    }
  }
  out[currentNode] = dfsCnt;
}
int GetOldLca(int x, int y) {
  if (depth[x] > depth[y]) {
    swap(x, y);
  }
  for (int k = lg2[n]; k >= 0; --k) {
    if (depth[y] - (1 << k) >= depth[x]) {
      y = spt[y][k];
    }
  }
  if (x == y) {
    return x;
  }
  for (int k = lg2[n]; k >= 0; --k) {
    if (spt[x][k] != spt[y][k]) {
      x = spt[x][k];
      y = spt[y][k];
    }
  }
  return spt[x][0];
}
int GetKthAncestor(int node, int k) {
  for (int i = lg2[n]; i >= 0; --i) {
    if (k >= (1 << i)) {
      node = spt[node][i];
      k -= (1 << i);
    }
  }
  return node;
}
bool IsAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
int GetNewLca(int x, int y, LazySegmentTree& tree, int root) {
  int oldLca = GetOldLca(x, y);
  if (IsAncestor(root, oldLca) || !IsAncestor(oldLca, root)) {
    return oldLca;
  } else if (IsAncestor(root, x) || IsAncestor(root, y)) {
    return root;
  } else {
    int lca1 = GetOldLca(root, x);
    int lca2 = GetOldLca(root, y);
    return (depth[lca1] >= depth[lca2] ? lca1 : lca2);
  }
}
void UpdateSubtree(int node, int value, LazySegmentTree& tree, int root) {
  if (node == root) {
    tree.add(1, n, value);
  } else if (IsAncestor(root, node) || !IsAncestor(node, root)) {
    tree.add(in[node], out[node], value);
  } else {
    int k = depth[root] - depth[node];
    int ancestor = GetKthAncestor(root, k - 1);
    tree.add(1, n, value);
    tree.add(in[ancestor], out[ancestor], -value);
  }
}
long long GetSubtreeSum(int node, LazySegmentTree& tree, int root) {
  if (node == root) {
    return tree.getSum(1, n);
  } else if (IsAncestor(root, node) || !IsAncestor(node, root)) {
    return tree.getSum(in[node], out[node]);
  } else {
    int k = depth[root] - depth[node];
    int ancestor = GetKthAncestor(root, k - 1);
    return tree.getSum(1, n) - tree.getSum(in[ancestor], out[ancestor]);
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int q;
  cin >> n >> q;
  for (int i = 1; i <= n; ++i) {
    cin >> sum[i];
  }
  for (int i = 0; i < n - 1; ++i) {
    int x, y;
    cin >> x >> y;
    adj[x].push_back(y);
    adj[y].push_back(x);
  }
  BuildLg2();
  Dfs(1);
  LazySegmentTree tree(n);
  int root = 1;
  while (q--) {
    int op;
    cin >> op;
    if (op == 1) {
      int node;
      cin >> node;
      root = node;
    } else if (op == 2) {
      int x, y, v;
      cin >> x >> y >> v;
      UpdateSubtree(GetNewLca(x, y, tree, root), v, tree, root);
    } else {
      int node;
      cin >> node;
      cout << GetSubtreeSum(node, tree, root) << "\n";
    }
  }
  return 0;
}
