树剖调不出来
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int res = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
res = res * 10 + ch - 48, ch = getchar();
return res * f;
}
const int maxn = 900001;
int head[maxn], cnt;
int dep[maxn], siz[maxn], f[maxn], top[maxn];
int n, m, son[maxn], id[maxn], rk[maxn];
struct edge
{
int to, nxt;
} e[maxn << 1];
int val[maxn];
inline void add(int from, int to)
{
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
struct node
{
int l, r, sum, tag;
#define sum(x) a[x].sum
#define tag(x) a[x].tag
} a[maxn];
#define ls p << 1
#define rs p << 1 | 1
inline void pushup(int p)
{
sum(p) = sum(ls) + sum(rs);
}
inline void dfs1(int u, int fa)
{
siz[u] = 1;
dep[u] = dep[fa] + 1;
for (register int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa)
continue;
f[v] = u;
dfs1(v, u);
siz[u] += siz[v];
if (siz[son[u]] < siz[v])
son[u] = v;
}
return;
}
inline void dfs2(int u, int tp)
{
top[u] = tp;
id[u] = ++cnt;
rk[cnt] = u;
if (!son[u])
return;
dfs2(son[u], tp);
for (register int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v != son[u] && v != f[u])
{
dfs2(v, v);
}
}
}
inline void build(int p, int l, int r)
{
a[p].l=l;
a[p].r=r;
if (l == r)
{
sum(p) = val[rk[l]];
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
a[p].l = a[ls].l;
a[p].r = a[rs].r;
pushup(p);
}
inline int get_len(int p)
{
return a[p].r - a[p].l + 1;
}
inline void pushdown(int p, int l, int r)
{
if (tag(p))
{
int mid = l + r >> 1;
a[ls].tag += a[p].tag;
a[rs].tag += a[p].tag;
sum(ls) += tag(p) * get_len(ls);
sum(rs) += tag(p) * get_len(rs);
tag(p) = 0;
}
}
inline void update(int p, int l, int r, int L, int R, int k)
{
if (L <= l && R >= r)
{
sum(p) += k * get_len(p);
tag(p) += k;
return;
}
pushdown(p, l, r);
int mid = l + r >> 1;
if (L <= mid)
update(ls, l, mid, L, R, k);
if (R > mid)
update(rs, mid + 1, r, L, R, k);
pushup(p);
return;
}
inline int query(int p, int l, int r, int L, int R)
{
if (L <= l && R >= r)
{
return sum(p);
}
pushdown(p, l, r);
int mid = l + r >> 1;
int ans = 0;
if (L <= mid)
ans += query(ls, l, mid, L, R);
if (R > mid)
ans += query(rs, mid + 1, r, L, R);
return ans;
}
inline int query_tree(int x, int y)
{
int res = 0;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x, y);
res += query(1, 1, n, id[top[x]], id[x]);
x = f[top[x]];
}
if (id[x] > id[y])
swap(x, y);
if (x != y)
res += query(1, 1, n, id[x], id[y]);
return res;
}
signed main()
{
n = read();
m = read();
for (register int i = 1; i <= n; i++)
val[i] = read();
for (register int x, y, i = 1; i < n; i++)
{
x = read();
y = read();
add(x, y);
add(y, x);
}
cnt = 0;
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
while (m--)
{
int opt = read();
int x = read();
if (opt == 1)
{
int y = read();
update(1, 1, n, id[x], id[x], y);
}
else if (opt == 2)
{
int y = read();
update(1, 1, n, id[x], id[x] + siz[x] - 1, y);
}
else if (opt == 3)
{
cout << query_tree(1, x) << endl;
}
}
return 0;
}