rt
#include <bits/stdc++.h>
#define f(i,a,b) for(int i = a ; i<=b ; i++)
using namespace std;
const int N=5e5+5;
vector<int> G[N];
int n,m;
int dep[N],fa[N],siz[N],son[N],top[N],ori[N];
int dfs_clock,id[N],u,v;
int a[N],w[N<<2],lzy[N];//扩大节点个数至4倍,避免RE
//建树
void pushup(int u){
w[u] = (w[2*u]+w[2*u+1]);//当前维护区间和,最大max,最小min
}
void build(int u/*father.id*/,int l,int r/*对应数列区间l~r*/){//分治建树
if(l == r){//有一个元素,直接赋值
w[u] = a[id[l]];
return ;
}
int mid = (l+r)>>1;
build(2*u ,l ,mid);
build(2*u+1,mid+1,r);
//更新当前节点w[u],合并两个子节点
pushup(u);
return ;
}
bool inrange(int L,int R,int l,int r){
//树节点LR是否被包含查询的lr?
//l L R r
return l<=L && R<=r;
}
bool outofrange(int L,int R,int l,int r){/*树节点LR是否被包含查询的l*//*l L R r*/return r<L || R<l;}
// 更新
void maketag(int u,int len,int x){//u树节点编号,len区间长度,x每个元素新增的值 lazy tag
lzy[u]+=x;
w[u]+=len*x;
}
void pushdown(int u,int l,int r){//下方
int mid = (l+r)/2;
maketag(2*u,mid-l+1,lzy[u]);
maketag(2*u+1,r-mid,lzy[u]);
lzy[u] = 0;
}
void update(int u,int L,int R,int l,int r,int x){
if(inrange(L,R,l,r)) maketag(u,R-L+1,x);
else if(!outofrange(L,R,l,r)){
int mid = (L+R)/2;
pushdown(u,L,R);
update(2*u,L,mid,l,r,x);
update(2*u+1,mid+1,R,l,r,x);
pushup(u);
}
}
//查询
int query(int u,int L,int R,int l,int r){
//uLR同上,查询区间lr
if(inrange(L,R,l,r)){
return w[u];
} else if(!outofrange(L,R,l,r)){//分治
int mid = (L+R)>>1;//对树节点进行分治!!!!,大写LR!!!!!!!!!!!
pushdown(u,L,R);
return query(2*u,L,mid,l,r)+query(2*u+1,mid+1,R,l,r);
}else{
return 0;
}
}
//轻重边划分
void dfs1(int u,int f){
dep[u]=dep[f]+1;//深度
fa[u]=f;//父节点
siz[u]=1;//子树大小
for(auto v:G[u]){
if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
//确定u的重儿子,siz最大
//son[u] u的重儿子 u->son[u]
if(!son[u]||siz[son[u]]<siz[v]){
son[u]=v;
}
}
}
//树形结构剖分为链式结构
//top[u]:u所在重链上的顶端节点编号
//id[u]:u在线性的节点序列中的位置下标
void dfs2(int u,int topu){
//u当前节点,topu,u在链中的 链头
id[u] = ++dfs_clock;
a[dfs_clock] = ori[u];
top[u]=topu;
if(!son[u]) return ;
//优先遍历重边
dfs2(son[u],top[u]);
for(auto v:G[u]){
if(v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
}
int query_range(int u,int v){//查询u,v
int ans = 0;
while(top[u]!=top[v]){//类似LCA的操作
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans+=query(1,1,n,id[top[u]],id[u]);
u = fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans+=query(1,1,n,id[u],id[v]);
return ans;
}
void update_range(int x,int y,int z){//查询u,v
while(top[x]!=top[y]){//类似LCA的操作
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],z);
x = fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],z);
}
int query_tree(int x){
return query(1,1,n,id[x],id[x]+siz[x]-1);
}
void update_tree(int x,int val){
update(1,1,n,id[x],id[x]+siz[x]-1,val);
}
int main(){
//// freopen("1.out","w",stdout);
cin>>n>>m;
f(i,1,n) cin>>ori[i];
f(i,1,n-1){
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
build(1,1,n);
while(m--){
int op,x,y,z;
cin>>op;
if(op == 1){
cin>>x>>y>>z;
update(1,1,n,id[x],id[x],y);
}else if(op == 2){
cin>>x>>y;
update(1,1,n,id[x],id[x]+siz[x]-1,y);
}else if(op == 3){
cin>>x;
cout<<query_range(1,x)<<endl;
}
}
return 0;
}