#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define int long long
const int maxn = 1000001;
int tot = 0, cnt = 0;
int siz[maxn], deep[maxn], son[maxn], fa[maxn], top[maxn];
int id[maxn], w[maxn], head[maxn], laz[maxn];
int num[maxn];
long long res = 0;
struct node {
int l, r, val;
} T[maxn << 2];
struct e {
int to, next;
} edge[maxn << 1];
inline void addedge(int x, int y) {
edge[++tot].to = y;
edge[tot].next = head[x];
head[x] = tot;
}
void up(int rt) {
T[rt].val = (T[rt << 1].val + T[rt << 1 | 1].val);
}
void dfs1(int x, int f) {
fa[x] = f;
deep[x] = deep[f] + 1;
siz[x] = 1;
int maxson = -1;
for (int i = head[x]; i!=0; i = edge[i].next) {
int y = edge[i].to;
if (y == f)
continue;
dfs1(y, x);
siz[x] = siz[x]+siz[y];
if (siz[y] > maxson) {
maxson = siz[y];
son[x] = y;
}
}
}
void dfs2(int x, int topf) {
top[x] = topf;
id[x] = ++cnt;
w[cnt] =num[x];
if (!son[x]) {
return ;
}
dfs2(son[x], topf);
for (int i = head[x]; i; i = edge[i].next) {
int y = edge[i].to;
if (y == fa[x] || y == son[x]) {
continue;
}
dfs2(y, y);
}
}
void build(int rt, int l, int r) {
laz[rt] = 0;
T[rt].l = l;
T[rt].r = r;
if (l == r) {
T[rt].val = w[l];
return;
}
int mid = (l + r) >> 1;;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
up(rt);
}
void pushdown(int rt) {
laz[rt << 1] += laz[rt];
laz[rt << 1 | 1] += laz[rt];
T[rt << 1].val += laz[rt << 1] * (T[rt << 1].r - T[rt << 1].l + 1);
T[rt << 1 | 1].val += laz[rt << 1 | 1] * (T[rt << 1 | 1].r - T[rt << 1 | 1].l + 1);
laz[rt] = 0;
}
void update_dian(int rt, int x, int d) {
if (T[rt].l == T[rt].r) {
T[rt].val += d;
return ;
}
if (laz[rt]) {
pushdown(rt);
}
int mid = (T[rt].l + T[rt].r) >> 1;
if (x <= mid) {
update_dian(rt << 1, x, d);
}
if (x > mid) {
update_dian(rt << 1 | 1, x, d);
}
up(rt);
}
void update_qu(int rt, int l, int r, int d) {
if (T[rt].l >= l && T[rt].r <= r) {
T[rt].val += (T[rt].r - T[rt].l + 1) * d;
laz[rt] += d;
return;
}
int mid = (T[rt].r + T[rt].l) >> 1;
if (laz[rt]) {
pushdown(rt);
}
if (l <= mid) {
update_qu(rt << 1, l, r, d);
}
if (r > mid) {
update_qu(rt << 1 | 1, l, r, d);
}
up(rt);
}
long long query(int rt, int l, int r) {
if (T[rt].l >= l && T[rt].r <= r) {
return T[rt].val;
}
long long ans=0;
int mid = (T[rt].l + T[rt].r) >> 1;
if (laz[rt]) {
pushdown(rt);
}
if (l <= mid) {
ans+=query(rt << 1, l, r);
}
if (r > mid) {
ans+=query(rt << 1 | 1, l, r);
}
return ans;
}
long long query_tree(int x) {
long long sum = 0;
while (top[x] != 1) {
sum += query(1, id[top[x]], id[x]);;
x = fa[top[x]];
}
sum+=query(1,id[top[x]],id[x]);
return sum;
}
signed main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> num[i];
}
for (int i = 1; i <= n - 1; i++) {
int x, y;
cin >> x >> y;
addedge(x, y);
addedge(y, x);
}
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
for (int i = 1; i <= m; i++) {
int opt, x, a;
cin >> opt;
if (opt == 1) {
cin >> x >> a;
update_dian(1, id[x], a);
}
if (opt == 2) {
cin >> x >> a;
update_qu(1, id[x], id[x] + siz[x]-1 , a);
}
if (opt == 3) {
cin >> x;
cout << query_tree(x) << endl;
}
}
}