#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
const int maxn=1e5+10;
vector<int> son[maxn];
bool ish[maxn];
int fa[maxn],depth[maxn],size[maxn],top[maxn],dfn[maxn],redfn[maxn],dfncnt=0;
long long val[maxn];
int hs[maxn],hv[maxn];
int n,m,r=1;
vector<int> to[maxn];
int grtotr_vis[maxn];
void addedge(int u,int v)
{
to[u].push_back(v);
to[v].push_back(u);
}
void inputs()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
}
void graphtotree(int x,int dp)
{
grtotr_vis[x]=1;
depth[x]=dp;
size[x]=1;
for(int i=0;i<to[x].size();i++)
{
if(!grtotr_vis[to[x][i]])
{
int s=to[x][i];
fa[s]=x;
son[x].push_back(s);
graphtotree(s,dp+1);
size[x]+=size[s];
if(size[s]>hv[x])
{
ish[hs[x]]=0;
ish[s]=1;
hs[x]=s;
hv[x]=size[s];
}
}
}
}
void dfs1(int x)
{
dfn[++dfncnt]=x;
if(ish[x])
{
top[x]=top[fa[x]];
}
else
{
top[x]=x;
}
if(hs[x]!=0)
{
dfs1(hs[x]);
for(int i=0;i<son[x].size();i++)
{
if(son[x][i]!=hs[x])
{
dfs1(son[x][i]);
}
}
}
}
long long a[maxn],sum_v[4*maxn],add_lazy[4*maxn];
void build(int p,int l,int r)
{
if(l==r)
{
sum_v[p]=a[l];
return ;
}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
sum_v[p]=sum_v[p*2]+sum_v[p*2+1];
}
void addf(int p,int l,int r,long long v)
{
add_lazy[p]=add_lazy[p]+v;
sum_v[p]=sum_v[p]+v*(r-l+1);
return ;
}
void pushdown(int p,int l,int r,int mid)
{
if(add_lazy[p]!=0)
{
addf(p*2,l,mid,add_lazy[p]);
addf(p*2+1,mid+1,r,add_lazy[p]);
add_lazy[p]=0;
}
}
void pluss(int p,int l,int r,int tl,int tr,long long v)
{
if(tl<=l && r<=tr) return addf(p,l,r,v);
int mid=(l+r)>>1;
pushdown(p,l,r,mid);
if(tl<=mid)
{
pluss(p*2,l,mid,tl,tr,v);
}
if(mid<tr)
{
pluss(p*2+1,mid+1,r,tl,tr,v);
}
sum_v[p]=sum_v[p*2]+sum_v[p*2+1];
}
long long query(int p,int l,int r,int tl,int tr)
{
if(tl<=l && r<=tr) return sum_v[p];
int mid=(l+r)>>1;
long long ret=0;
pushdown(p,l,r,mid);
if(tl<=mid)
{
ret=ret+query(p*2,l,mid,tl,tr);
}
if(mid<tr)
{
ret=ret+query(p*2+1,mid+1,r,tl,tr);
}
return ret;
}
long long heavyquery(int x,int y)
{
if(depth[x]>depth[y])
{
int t=x;x=y;y=t;
}
return query(1,1,n,redfn[x],redfn[y]);
}
void heavyplus(int x,int y,long long v)
{
if(depth[x]>depth[y])
{
int t=x;x=y;y=t;
}
pluss(1,1,n,redfn[x],redfn[y],v);
}
long long pathquery(int x,int y)
{
long long ans=0;
while(top[x]!=top[y])
{
if(depth[top[x]]>=depth[top[y]])
{
ans=ans+heavyquery(top[x],x);
x=top[x];
if(x!=r) x=fa[x];
}
else
{
ans=ans+heavyquery(top[y],y);
y=top[y];
if(y!=r) y=fa[y];
}
}
ans=ans+heavyquery(x,y);
return ans;
}
void pathplus(int x,int y,long long v)
{
while(top[x]!=top[y])
{
if(depth[top[x]]>=depth[top[y]])
{
heavyplus(top[x],x,v);
x=top[x];
if(x!=r) x=fa[x];
}
else
{
heavyplus(top[y],y,v);
y=top[y];
if(y!=r) y=fa[y];
}
}
heavyplus(x,y,v);
}
long long subquery(int x)
{
return query(1,1,n,redfn[x],redfn[x]+size[x]-1);
}
void subplus(int x,long long v)
{
pluss(1,1,n,redfn[x],redfn[x]+size[x]-1,v);
}
int main()
{
inputs();
graphtotree(r,1);
dfs1(r);
for(int i=1;i<=n;i++)
{
redfn[dfn[i]]=i;
a[i]=val[dfn[i]];
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x,y;
scanf("%d%d",&x,&y);
pathplus(x,x,y);
}
else if(op==2)
{
int x,y;
scanf("%d%d",&x,&y);
subplus(x,y);
}
else if(op==3)
{
int x;
scanf("%d",&x);
printf("%lld\n",pathquery(1,x));
}
}
return 0;
}