#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n, m, cnt;
int a[N], now[N];
int head[N], nxt[N], to[N];
int fa[N], dep[N], son[N], siz[N], top[N], id[N];
int tr[N * 4], add[N * 4];
void add_edge(int x, int y)
{
cnt++;
nxt[cnt] = head[x];
to[cnt] = y;
head[x] = cnt;
}
void dfs1(int x, int f)
{
fa[x] = f;
dep[x] = dep[f] + 1;
siz[x] = 1;
for(int i = head[x]; i; i = nxt[i])
{
if(to[i] == f) continue;
dfs1(to[i], x);
siz[x] += siz[to[i]];
if(siz[son[x]] < siz[to[i]]) son[x] = to[i];
}
}
void dfs2(int x, int tp)
{
id[x] = ++cnt;
now[cnt] = a[x];
top[x] = tp;
if(!son[x]) return;
dfs2(son[x], tp);
for(int i = head[x]; i; i = nxt[i])
{
if(id[to[i]]) continue;
dfs2(to[i], to[i]);
}
}
void pushup(int x)
{
tr[x] = tr[x << 1] + tr[x << 1 | 1];
}
void build(int x, int l, int r)
{
if(l == r) {tr[x] = now[l]; return;}
int mid = l + r >> 1;
build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);
pushup(x);
}
void change(int x, int l, int r, int sum)
{
tr[x] += (r - l + 1) * sum;
add[x] += sum;
}
void pushdown(int x, int l, int r)
{
int mid = l + r >> 1;
change(x << 1, l, mid, add[x]);
change(x << 1 | 1, mid + 1, r, add[x]);
add[x] = 0;
}
void update(int x, int l, int r, int ql, int qr, int k)
{
if(ql <= l && r <= qr) {change(x, l, r, k); return;}
int mid = l + r >> 1;
pushdown(x, l, r);
if(ql <= mid) update(x << 1, l, mid, ql, qr, k);
if(qr > mid) update(x << 1 | 1, mid + 1, r, ql, qr, k);
pushup(x);
}
int query(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return tr[x];
int mid = l + r >> 1, ans = 0;
pushdown(x, l, r);
if(ql <= mid) ans += query(x << 1, l, mid, ql, qr);
if(qr > mid) ans += query(x << 1 | 1, mid + 1, r, ql, qr);
return ans;
}
void update_point(int x, int k)
{
update(1, 1, n, id[x], id[x], k);
}
void update_son(int x, int k)
{
update(1, 1, n, id[x], id[x] + siz[x] - 1, k);
}
int query_tree(int x, int y)
{
int ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans += query(1, 1, n, id[top[x]], id[x]);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ans += query(1, 1, n, id[x], id[y]);
return ans;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i < n; i++)
{
int x, y;
cin >> x >> y;
add_edge(x, y), add_edge(y, x);
}
cnt = 0;
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
while(m--)
{
int op;
cin >> op;
if(op == 1)
{
int x, k;
cin >> x >> k;
update_point(x, k);
}
if(op == 2)
{
int x, k;
cin >> x >> k;
update_son(x, k);
}
if(op == 3)
{
int x;
cin >> x;
cout << query_tree(x, 1) << "\n";
}
}
return 0;
}