rt
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
vector<int> g[N];
int a[N];
int dfn[N];
int fa[N];
int siz[N];
int son[N];
int dep[N];
int top[N];
int bot[N];
int rnk[N];
void dfs1(int o)
{
siz[o]=1;
son[o]=-1;
for(int e:g[o])
{
if(e!=fa[o])
{
dep[e]=dep[o]+1;
fa[e]=o;
siz[e]=1;
dfs1(e);
siz[o]+=siz[e];
if(son[o]==-1||siz[son[o]]<siz[e])son[o]=e;
}
}
}
int cnt;
void dfs2(int tot,int o)
{
dfn[o]=++cnt;
rnk[cnt]=o;
top[o]=tot;
bot[o]=cnt;
if(son[o]!=-1)
{
dfs2(tot,son[o]);
bot[o]=bot[son[o]];
}
for(int e:g[o])
{
if(e!=son[o]&&e!=fa[o])
{
dfs2(e,e);
bot[o]=bot[e];
}
}
}
struct Node
{
int l,r,v,lazy;
};
struct Tree
{
Node tr[N<<2];
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)
void pushup(int rt)
{
tr[rt].v=tr[lson].v+tr[rson].v;
}
void pushdown(int rt)
{
int k=tr[rt].lazy;
tr[lson].v+=(tr[lson].r-tr[lson].l+1)*k;
tr[lson].lazy+=k;
tr[rson].v+=(tr[rson].r-tr[rson].l+1)*k;
tr[rson].lazy+=k;
tr[rt].lazy=0;
}
void build(int rt,int l,int r)
{
tr[rt]={l,r};
if(l==r)
{
tr[rt].v=a[rnk[l]];
return ;
}
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
int query(int rt,int st,int ed)
{
int l=tr[rt].l,r=tr[rt].r;
if(st<=l&&r<=ed)
{
return tr[rt].v;
}
pushdown(rt);
if(ed<=mid)
{
return query(lson,st,ed);
}
if(mid<st)
{
return query(rson,st,ed);
}
int L=query(lson,st,ed);
int R=query(rson,st,ed);
return L+R;
}
void update(int rt,int st,int ed,int k)
{
int l=tr[rt].l,r=tr[rt].r;
if(st<=l&&r<=ed)
{
tr[rt].v+=(r-l+1)*k;
tr[rt].lazy+=k;
return ;
}
pushdown(rt);
if(st<=mid)
{
update(lson,st,ed,k);
}
if(mid<ed)
{
update(rson,st,ed,k);
}
pushup(rt);
}
#undef lson
#undef rson
#undef mid
}tree;
void add_subtree(int x,int k)
{
tree.update(1,dfn[x],bot[x],k);
}
void add_point(int x,int k)
{
tree.update(1,dfn[x],dfn[x],k);
}
int query_path(int x)
{
int y=1;
int res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
res+=tree.query(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dfn[x]<dfn[y])
{
swap(x,y);
}
res+=tree.query(1,y,x);
return res;
}
int m;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dep[1]=1;
dfs1(1);
dfs2(1,1);
tree.build(1,1,n);
while(m--)
{
int op,x;
cin>>op>>x;
if(op==1)
{
int k;
cin>>k;
add_point(x,k);
}
else if(op==2)
{
int k;
cin>>k;
add_subtree(x,k);
}
else
{
cout<<query_path(x)<<endl;;
}
// for(int i=1;i<=n;i++)
// {
// cout<<tree.query(1,dfn[i],dfn[i])<<" ";
// }
// cout<<endl;
}
return 0;
}