#include <bits/stdc++.h>   using namespace std;   const int maxn = 1e5 + 10;   int n;   int a[maxn];   int nivel[maxn], in[maxn], out[maxn], tt;   vector<int> grafo[maxn];   struct BinaryLifting {     int tab[maxn][20];     void dfs(int u, int p) {       in[u] = ++tt;       for (auto v : grafo[u]) {         if (v == p) continue;         nivel[v] = nivel[u] + 1, tab[v][0] = u;         dfs(v, u);       }       out[u] = tt;     }     void build(void) {       for (int j = 1; j < 20; j++)         for (int i = 1; i <= n; i++) tab[i][j] = tab[tab[i][j - 1]][j - 1];     }     int intersect(int u, int v, int w_u, int w_v) {       if (nivel[u] < nivel[v]) swap(u, v), swap(w_u, w_v);       for (int i = 19; i >= 0; i--)         if (nivel[u] - (1 << i) >= nivel[v] && w_u >= (1 << i))           u = tab[u][i], w_u -= (1 << i);       if (nivel[u] != nivel[v]) return -1;       if (u == v) return u;       for (int i = 19; i >= 0; i--)         if (tab[u][i] && tab[v][i] && tab[u][i] != tab[v][i] &&             min(w_u, w_v) >= (1 << i))           u = tab[u][i], v = tab[v][i], w_u -= (1 << i), w_v -= (1 << i);       if (tab[u][0] != tab[v][0] || min(w_u, w_v) == 0) return -1;       return tab[u][0];     }     int dist(int u, int v) {       return nivel[u] + nivel[v] - 2 * nivel[intersect(u, v, nivel[u], nivel[v])];     }     int get_intersection(int u, int v, int root) {       int k = -1;       int lca_u = intersect(u, root, nivel[u], nivel[root]);       int lca_v = intersect(v, root, nivel[v], nivel[root]);       int aux = intersect(u, v, nivel[u] - nivel[lca_u], nivel[v] - nivel[lca_v]);       if (k == -1 || (aux != -1 && dist(aux, root) > dist(k, root))) k = aux;       aux =           intersect(u, root, nivel[u] - nivel[lca_u], nivel[root] - nivel[lca_v]);       if (k == -1 || (aux != -1 && dist(aux, root) > dist(k, root))) k = aux;       aux =           intersect(root, v, nivel[root] - nivel[lca_u], nivel[v] - nivel[lca_v]);       if (k == -1 || (aux != -1 && dist(aux, root) > dist(k, root))) k = aux;       aux = intersect(root, root, nivel[root] - nivel[lca_u],                       nivel[root] - nivel[lca_v]);       if (k == -1 || (aux != -1 && dist(aux, root) > dist(k, root))) k = aux;       return k;     }     int kth(int u, int k) {       for (int i = 19; i >= 0; i--)         if (tab[u][i] && k >= (1 << i)) u = tab[u][i], k -= (1 << i);       return u;     }   } LCA;   struct SegmentTree {     long long tree[3 * maxn], lazy[3 * maxn];     void flush(int node, int l, int r) {       if (!lazy[node]) return;       if (l != r) {         lazy[2 * node] += lazy[node];         lazy[2 * node + 1] += lazy[node];       }       tree[node] += 1ll * (r - l + 1) * lazy[node];       lazy[node] = 0;     }     void upd(int node, int l, int r, int a, int b, int v) {       flush(node, l, r);       if (l > b || r < a) return;       if (l >= a && r <= b) {         lazy[node] = 1ll * v;         flush(node, l, r);         return;       }       int mid = (l + r) >> 1;       upd(2 * node, l, mid, a, b, v);       upd(2 * node + 1, mid + 1, r, a, b, v);       tree[node] = tree[2 * node] + tree[2 * node + 1];     }     long long query(int node, int l, int r, int a, int b) {       flush(node, l, r);       if (l > b || r < a) return 0;       if (l >= a && r <= b) return tree[node];       int mid = (l + r) >> 1;       return query(2 * node, l, mid, a, b) +              query(2 * node + 1, mid + 1, r, a, b);     }   } seg;   bool is_ancestor(int u, int v) { return (in[v] >= in[u] && out[v] <= out[u]); }   int main(void) {     int q;     scanf( %d %d , &n, &q);     for (int i = 1; i <= n; i++) scanf( %d , &a[i]);     for (int i = 1; i < n; i++) {       int u, v;       scanf( %d %d , &u, &v);       grafo[u].push_back(v);       grafo[v].push_back(u);     }     LCA.dfs(1, 0);     LCA.build();     for (int i = 1; i <= n; i++) seg.upd(1, 1, n, in[i], in[i], a[i]);     int root = 1;     while (q--) {       int op;       scanf( %d , &op);       if (op == 1) {         int v;         scanf( %d , &v);         root = v;       } else if (op == 2) {         int u, v, x;         scanf( %d %d %d , &u, &v, &x);         int k = LCA.get_intersection(u, v, root);         if (!is_ancestor(k, root))           seg.upd(1, 1, n, in[k], out[k], x);         else {           seg.upd(1, 1, n, 1, n, x);           if (k != root) {             int w = LCA.kth(root, nivel[root] - nivel[k] - 1);             seg.upd(1, 1, n, in[w], out[w], -x);           }         }       } else {         int u;         scanf( %d , &u);         if (!is_ancestor(u, root))           printf( %lld n , seg.query(1, 1, n, in[u], out[u]));         else {           if (u == root)             printf( %lld n , seg.query(1, 1, n, 1, n));           else {             int w = LCA.kth(root, nivel[root] - nivel[u] - 1);             printf( %lld n ,                    seg.query(1, 1, n, 1, n) - seg.query(1, 1, n, in[w], out[w]));           }         }       }     }   }   