RT,谢谢巨佬们QAQ
#include<iostream>
#include<cstdio>
#define ls(p) p<<1
#define rs(p) p<<1|1
#define ll long long
#define fo(i,x,y) for(register int i=x;i<=y;++i)
#define go(i,x,y) for(register int i=x;i>=y;--i)
using namespace std;
inline int read(){ int x=0,fh=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') fh=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } return x*fh; }
//建树->dfs1预处理出必备信息(siz,dep,f,son)->dfs2进行轻重链剖分(求出每一个点所在重链的链头结点以及dfs序)
//套一棵线段树
const int maxn=1e5+5;
struct Edge{
int to,next;
}e[maxn<<1];
int tot,head[maxn],n,m,val[maxn];
void connect(int x,int y){
e[++tot]=(Edge){y,head[x]};
head[x]=tot;
}
int f[maxn],dep[maxn],siz[maxn],son[maxn];
void dfs1(int now,int fa){
f[now]=fa;
dep[now]=dep[fa]+1;
siz[now]=1;
int mx=0;
for(int i=head[now];i;i=e[i].next){
int p=e[i].to;
if(p==fa) continue;
dfs1(p,now);
siz[now]+=siz[p];
if(siz[p]>mx){
mx=p;
son[now]=p;
}
}
}
int dfn[maxn],t,pos[maxn],top[maxn];
void dfs2(int now,int chain){
top[now]=chain;
dfn[now]=++t;
pos[t]=now;
if(son[now]) dfs2(son[now],chain);
for(int i=head[now];i;i=e[i].next){
int p=e[i].to;
if(p==f[now]||p==son[now]) continue;
dfs2(p,p);
}
}
struct Node{
int Lef,Rig;
ll tag,val;
}tree[maxn<<2];
void push_up(int now){
tree[now].val=tree[ls(now)].val+tree[rs(now)].val;
}
void push_down(int now){
int lt=ls(now),rt=rs(now);
tree[lt].tag+=tree[now].tag;
tree[lt].val+=(tree[lt].Rig-tree[lt].Lef+1)*tree[now].tag;
tree[rt].tag+=tree[now].tag;
tree[rt].val+=(tree[rt].Rig-tree[rt].Lef+1)*tree[now].tag;
tree[now].tag=0;
}
void build(int now,int L,int R){
tree[now].Lef=L,tree[now].Rig=R;
if(L==R){
tree[now].val=val[pos[L]];
return;
}
int mid=(L+R)>>1;
build(ls(now),L,mid);
build(rs(now),mid+1,R);
push_up(now);
}
void update(int now,int aim_L,int aim_R,ll k){
if(tree[now].Lef>=aim_L&&tree[now].Rig<=aim_R){
tree[now].tag+=k;
tree[now].val+=(tree[now].Rig-tree[now].Lef+1)*k;
return;
}
if(tree[now].tag) push_down(now);
int mid=(tree[now].Lef+tree[now].Rig)>>1;
if(aim_L<=mid) update(ls(now),aim_L,aim_R,k);
if(aim_R>mid) update(rs(now),aim_L,aim_R,k);
push_up(now);
}
ll ask(int now,int aim_L,int aim_R){
if(tree[now].Lef>=aim_L&&tree[now].Rig<=aim_R) return tree[now].val;
int mid=(tree[now].Lef+tree[now].Rig)>>1;
ll ret=0;
if(tree[now].tag) push_down(now);
if(aim_L<=mid) ret+=ask(ls(now),aim_L,aim_R);
if(aim_R>mid) ret+=ask(rs(now),aim_L,aim_R);
return ret;
}
void change_point(int now,ll k){
update(1,dfn[now],dfn[now],k);
}
void change_subtree(int now,ll k){
update(1,dfn[now],dfn[now]+siz[now]-1,k);
}
ll ask_chain(int now){
ll ret=0;
while(dep[top[now]]>1){
ret+=ask(1,dfn[top[now]],dfn[now]);
now=f[top[now]];
}
ret+=ask(1,1,dfn[now]);
return ret;
}
int main(){
n=read(),m=read();
fo(i,1,n) val[i]=read();
fo(i,1,n-1){
int x=read(),y=read();
connect(x,y);
connect(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
fo(i,1,m){
int opt=read(),x=read();
if(opt==1){
int k=read();
change_point(x,k);
}
if(opt==2){
int k=read();
change_subtree(x,k);
}
if(opt==3){
printf("%lld\n",ask_chain(x));
}
}
return 0;
}