#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 110000;
int n, m;
int a[N];
int cnt;
int in[N], out[N];
int sum[N << 1];
pair<int, int> ops[N << 1];
vector<int> e[N];
struct node {
int l, r;
int lz;
int sum;
} tree[N << 3];//本来是2*n,四倍空间是 8*n
void push_up(int u) {
tree[u].sum = tree[u << 1].sum + tree[u << 1 | 1].sum;//上传
}
void push_down(int u) {
if (tree[u].lz) {//下传懒惰标记
tree[u << 1].sum += (sum[tree[u << 1].r] - sum[tree[u << 1].l - 1]) * tree[u].lz;
tree[u << 1 | 1].sum += (sum[tree[u << 1 | 1].r] - sum[tree[u << 1 | 1].l - 1]) * tree[u].lz;
tree[u << 1].lz += tree[u].lz;
tree[u << 1 | 1].lz += tree[u].lz;
tree[u].lz = 0;
}
}
void dfs(int u, int fa) {
in[u] = ++cnt;//在2*n的序列中u的入队位置在cnt
ops[cnt] = make_pair(u, 1);//当前位置的节点为u,入队为1
for (int v : e[u]) {
if (v != fa) {
dfs(v, u);
}
}
out[u] = ++cnt;//在序列中u的出队位置在cnt
ops[cnt] = make_pair(u, -1);//当前位置的节点为u,出队为-1
}
void build(int u, int l, int r) {
tree[u].l = l, tree[u].r = r;//左右子树
if (l == r) {
tree[u].sum = ops[l].second * a[ops[l].first];//当前节点的值
return ;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void add(int u, int id, int k) {
if (tree[u].l == tree[u].r) {//已经找到了
tree[u].sum += k;
return ;
}
push_down(u);//下传
if (id <= tree[u << 1].r) add(u << 1, id, k);
else add(u << 1 | 1, id, k);
push_up(u);
}
void update(int u, int l, int r, int k) {
if (l <= tree[u].l && tree[u].r <= r) {//在范围内
tree[u].lz += k;//懒惰标记
tree[u].sum += (sum[tree[u].r] - sum[tree[u].l - 1]) * k;//当前节点个数*节点增加数目k
return ;
}
push_down(u);//下传
if (l <= tree[u << 1].r) update(u << 1, l, r, k);
if (r >= tree[u << 1 | 1].l) update(u << 1 | 1, l, r, k);
push_up(u);
}
int query(int u, int l, int r) {
if (tree[u].l <= l && tree[u].r <= r) {
return tree[u].sum;//找到区间范围
}
push_down(u);//下传
int s = 0;
if (l <= tree[u << 1].r) s += query(u << 1, l, r);
if (r >= tree[u << 1 | 1].l) s += query(u << 1 | 1, l, r);
return s;
}
signed main() {
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
for (int i = 1; i < n; i++) {
int u, v;
scanf("%lld%lld", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, -1);
for (int i = 1; i <= (n << 1); i++) {
sum[i] = sum[i - 1] + ops[i].second;//在2*n的序列中计算进出队列的前缀和来计算区间内的点个数
}
build(1, 1, n << 1);//线段树建树
while (m--) {
int op;
scanf("%lld", &op);
if (op == 1) {
int x, y;
scanf("%lld%lld", &x, &y);
add(1, in[x], y);//将x入队的节点值+y
add(1, out[x], -y);//将x出队的节点值-y
} else if (op == 2) {
int x, y;
scanf("%lld%lld", &x, &y);
update(1, in[x], out[x], y);//将x的子树[in[x],out[x]]全部+y
} else {
int x;
scanf("%lld", &x);
printf("%lld\n", query(1, 1, in[x]));
}
}
return 0;
}
WA&RE 0pts.