#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
namespace SLPF{
#define N 100001
int dep[N],fa[N],son[N],id[N],size[N],cost[N],top[N],_cost[N];
int n,m,x,y,root,mod=0x7fffffff,tc,ans;
vector<int>l[N];
void dfs(int v,int d,int f) {
fa[v]=f;
dep[v]=d;
size[v]=1;
int Maxs=-1;
for(int i=0; i<l[v].size(); i++) {
int u=l[v][i];
if(u==f)continue;
dfs(u,d+1,v);
size[v]+=size[u];
if(size[u]>Maxs) {
Maxs=size[u];
son[v]=u;
}
}
}
void dfs2(int v,int topv) {
id[v]=++tc;
top[v]=topv;
_cost[tc]=cost[v];
if(!son[v])return ;
dfs2(son[v],topv);
for(int i=0; i<l[v].size(); i++) {
int u=l[v][i];
if(u==fa[v]||u==son[v])continue;
dfs2(u,u);
}
}
struct tree {
#define lc now<<1
#define rc now<<1|1
struct node {
int data,add,l,r;
} a[N<<2];
void build(int l,int r,int now) {
a[now].l=l;
a[now].r=r;
if(l==r) {
a[now].data=_cost[l];
a[now].data%=mod;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lc);
build(mid+1,r,rc);
a[now].data=a[lc].data+a[rc].data;
}
void pushdown(int now) {
if(a[now].add) {
a[lc].data+=a[now].add*(a[lc].r-a[lc].l+1);
a[lc].add+=a[now].add;
a[rc].data+=a[now].add*(a[rc].r-a[rc].l+1);
a[rc].add+=a[now].add;
a[now].add=0;
}
}
void _Change(int l,int r,int now,int ad) {
if(a[now].l>=l&&a[now].r<=r) {
a[now].data+=ad*(a[now].r-a[now].l+1);
a[now].add+=ad;
return ;
}
pushdown(now);
int mid=((a[now].l+a[now].r)>>1);
if(l<=mid)_Change(l,r,lc,ad);
if(r>mid) _Change(l,r,rc,ad);
a[now].data=a[lc].data+a[rc].data;
}
void _Cal(int l,int r,int now) {
if(a[now].l>=l&&a[now].r<=r) {
ans+=a[now].data;
return ;
}
pushdown(now);
int mid=((a[now].l+a[now].r)>>1);
if(l<=mid)_Cal(l,r,lc);
if(r>mid)_Cal(l,r,rc);
}
}tr;
void swap(int &x,int &y){
int t=x;x=y;y=t;
}
int qPoint(int x,int y){
ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
tr._Cal(id[top[x]],id[x],1);
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
tr._Cal(id[x],id[y],1);
ans%=mod;
return ans;
}
void uPoint(int x,int y,int ad){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
tr._Change(id[top[x]],id[x],1,ad);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
tr._Change(id[x],id[y],1,ad);
}
int qTree(int x){
ans=0;
tr._Cal(id[x],id[x]+size[x]-1,1);
return ans;
}
void uTree(int x,int ad){
tr._Change(id[x],id[x]+size[x]-1,1,ad);
}
}
using namespace SLPF;
int main() {
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>cost[i];
for(int i=1; i<n; i++) {
cin>>x>>y;
l[x].push_back(y);
l[y].push_back(x);
}
root=1;
dfs(root,1,-1);
dfs2(root,root);
tr.build(1,n,1);
for(int i=1;i<=m;i++){
int p,x,y,z;
cin>>p;
switch(p){
case 1:{
cin>>x>>z;
uPoint(x,x,z);
break;
}
case 2:{
cin>>x>>y;
uTree(x,y);
break;
}
case 3:{
cin>>x;
cout<<qPoint(x,1)<<endl;
break;
}
}
}
}