#include <bits/stdc++.h>   using namespace std;   inline long long read() {     long long x = 0, f = 1;     char ch = getchar();     while (!isdigit(ch)) {       if (ch ==  - ) f = -1;       ch = getchar();     }     while (isdigit(ch)) {       x = x * 10 + ch - 48;       ch = getchar();     }     return x * f;   }   long long n, k;   long long st[200001];   struct aa {     long long u, v;     long long next;   } edge[200001 * 4];   long long head[200001];   long long cnt = 0;   void add_edge(long long u, long long v) {     cnt++;     edge[cnt].u = u;     edge[cnt].v = v;     edge[cnt].next = head[u];     head[u] = cnt;   }   long long root = 0;   long long f[200001][29];   long long son[200001];   long long size[200001];   long long depth[200001];   long long ed[200001];   long long tot = 0;   long long id[200001];   long long top[200001];   void dfs1(long long u, long long fa) {     f[u][0] = fa;     for (long long i = 1; i <= 21; i++) {       f[u][i] = f[f[u][i - 1]][i - 1];     }     depth[u] = depth[fa] + 1;     size[u] = 1;     for (long long i = head[u]; i; i = edge[i].next) {       long long v = edge[i].v;       if (v != fa) {         dfs1(v, u);         if (size[son[u]] < size[v]) {           son[u] = v;         }         size[u] += size[v];       }     }   }   void dfs2(long long u, long long tp) {     tot++;     id[u] = tot;     ed[tot] = st[u];     top[u] = tp;     if (son[u]) {       dfs2(son[u], tp);       for (long long i = head[u]; i; i = edge[i].next) {         long long v = edge[i].v;         if (v != son[u] && v != f[u][0]) {           dfs2(v, v);         }       }     }   }   struct qw {     long long l, r, val;     long long add;   } a[1600001];   void up(long long i) { a[i].val = a[i * 2].val + a[i * 2 + 1].val; }   void down(long long i) {     long long x = a[i].add;     a[i * 2].add += x;     a[i * 2 + 1].add += x;     a[i * 2].val += (a[i * 2].r - a[i * 2].l + 1) * x;     a[i * 2 + 1].val += (a[i * 2 + 1].r - a[i * 2 + 1].l + 1) * x;     a[i].add = 0;   }   void build(long long i, long long l, long long r) {     a[i].l = l;     a[i].r = r;     if (l == r) {       a[i].val = ed[a[i].l];       return;     }     long long mid = (l + r) / 2;     build(i * 2, l, mid);     build(i * 2 + 1, mid + 1, r);     up(i);   }   void update(long long i, long long l, long long r, long long k) {     if (a[i].l == l && a[i].r == r) {       a[i].add += k;       a[i].val += (a[i].r - a[i].l + 1) * k;       return;     }     down(i);     long long mid = (a[i].l + a[i].r) / 2;     if (mid >= r) {       update(i * 2, l, r, k);     } else {       if (mid < l) {         update(i * 2 + 1, l, r, k);       } else {         update(i * 2, l, mid, k);         update(i * 2 + 1, mid + 1, r, k);       }     }     up(i);   }   long long query(long long i, long long l, long long r) {     if (a[i].l == l && a[i].r == r) {       return a[i].val;     }     down(i);     long long mid = (a[i].l + a[i].r) / 2;     if (mid >= r) {       return query(i * 2, l, r);     } else {       if (mid < l) {         return query(i * 2 + 1, l, r);       } else {         return (query(i * 2, l, mid) + query(i * 2 + 1, mid + 1, r));       }     }   }   long long find(long long u, long long to) {     for (long long i = 21; i >= 0; i--) {       if (depth[f[u][i]] > depth[to]) {         u = f[u][i];       }     }     return u;   }   long long lca(long long x, long long y) {     if (depth[x] < depth[y]) {       swap(x, y);     }     while (depth[x] > depth[y]) {       x = f[x][(long long)log2(depth[x] - depth[y])];     }     if (x == y) {       return x;     }     for (long long i = 21; i >= 0; i--) {       if (f[x][i] != f[y][i]) {         x = f[x][i];         y = f[y][i];       }     }     return f[x][0];   }   long long lcaq(long long x, long long y) {     long long v1 = lca(x, y);     long long v2 = lca(x, root);     long long v3 = lca(y, root);     if (depth[v1] < depth[v2]) {       v1 = v2;     }     if (depth[v1] < depth[v3]) {       v1 = v3;     }     return v1;   }   signed main() {     cin >> n >> k;     for (long long i = 1; i <= n; i++) {       cin >> st[i];     }     for (long long i = 1; i <= n - 1; i++) {       long long u, v;       cin >> u >> v;       add_edge(u, v);       add_edge(v, u);     }     root = 1;     dfs1(1, 0);     dfs2(1, 1);     build(1, 1, n);     for (long long i = 1; i <= k; i++) {       long long opt;       opt = read();       if (opt == 1) {         long long v;         cin >> v;         root = v;       }       if (opt == 2) {         long long a, b, k;         cin >> a >> b >> k;         long long x = lcaq(a, b);         if (x == root) {           update(1, 1, n, k);         } else {           if (id[root] >= id[x] && id[root] <= id[x] + size[x] - 1) {             long long at = find(root, x);             update(1, 1, n, k);             update(1, id[at], id[at] + size[at] - 1, -k);           } else {             update(1, id[x], id[x] + size[x] - 1, k);           }         }       }       if (opt == 3) {         long long x;         cin >> x;         if (x == root) {           cout << query(1, 1, n) << endl;           ;         } else {           if (id[root] >= id[x] && id[root] <= id[x] + size[x] - 1) {             long long at = find(root, x);             long long val =                 query(1, 1, n) - query(1, id[at], id[at] + size[at] - 1);             cout << val << endl;           } else {             cout << query(1, id[x], id[x] + size[x] - 1) << endl;             ;           }         }       }     }     return 0;   }