#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10,mod=1e9+7;
struct SegTree
{
int l,r,sum,lazy;
}tr[N*4];
vector<int>adj[N];
int tot,fa[N],dep[N],siz[N],hson[N],top[N],seg[N],rev[N],x[N];
void pushup(int u)
{
tr[u].sum=tr[u*2].sum+tr[u*2+1].sum;
}
void pushdown(int u)
{
tr[u*2].lazy+=tr[u].lazy;
tr[u*2].sum+=(tr[u*2].r-tr[u*2].l+1)*tr[u].lazy;
tr[u*2+1].lazy+=tr[u].lazy;
tr[u*2+1].sum+=(tr[u*2+1].r-tr[u*2+1].l+1)*tr[u].lazy;
tr[u].lazy=0;
}
void build_tree(int u,int l,int r)
{
tr[u].l=l;
tr[u].r=r;
if(l==r)
{
tr[u].sum=x[rev[l]];
return;
}
int mid=(l+r)>>1;
build_tree(u*2,l,mid);
build_tree(u*2+1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int x)
{
if(l<=tr[u].l&&tr[u].r<=r)
{
if(tr[u].l!=tr[u].r) tr[u].lazy+=x;
tr[u].sum+=(tr[u].r-tr[u].l+1)*x;
return;
}
pushdown(u);
int mid=(tr[u].l+tr[u].r)>>1;
if(l<=mid) modify(u*2,l,r,x);
if(r>mid) modify(u*2+1,l,r,x);
pushup(u);
}
int query(int u,int l,int r)
{
if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
pushdown(u);
int ans=0;
int mid=(tr[u].l+tr[u].r)>>1;
if(l<=mid) ans+=query(u*2,l,r);
if(r>mid) ans+=query(u*2+1,l,r);
return ans;
}
void dfs1(int u,int f)
{
fa[u]=f;
dep[u]=dep[f]+1;
siz[u]=1;
int mxn=0;
for(auto v:adj[u])
{
if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>mxn) mxn=siz[v],hson[u]=v;
}
}
void dfs2(int u)
{
if(hson[u])
{
top[hson[u]]=top[u];
seg[hson[u]]=++tot;
rev[tot]=hson[u];
dfs2(hson[u]);
}
for(auto v:adj[u])
{
if(v==fa[u]||v==hson[u]) continue;
top[v]=v;
seg[v]=++tot;
rev[tot]=v;
dfs2(v);
}
}
void mtr(int u,int x)
{
modify(1,seg[u],seg[u]+siz[u]-1,x);
}
int qtr(int u)
{
return query(1,seg[u],seg[u]+siz[u]-1);
}
void mpath(int x,int y,int v)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[x]<dep[y]) swap(x,y),swap(fx,fy);
modify(1,seg[fx],seg[x],v);
x=fa[fx];
fx=top[x];
}
if(dep[x]<dep[y]) swap(x,y);
modify(1,seg[y],seg[x],v);
}
int qpath(int x,int y)
{
int fx=top[x],fy=top[y];
int ans=0;
while(fx!=fy)
{
if(dep[x]<dep[y]) swap(x,y),swap(fx,fy);
ans+=query(1,seg[fx],seg[x]);
x=fa[fx];
fx=top[x];
}
if(dep[x]<dep[y]) swap(x,y);
ans+=query(1,seg[y],seg[x]);
return ans;
}
signed main()
{
int n,m,r,p;
cin>>n>>m>>r>>p;
for(int i=1;i<=n;i++) cin>>x[i];
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs1(r,0);
top[r]=r;
seg[r]=++tot;
rev[tot]=r;
dfs2(r);
build_tree(1,1,n);
while(m--)
{
int op;
cin>>op;
if(op==1)
{
int x,y,z;
cin>>x>>y>>z;
mpath(x,y,z);
}
if(op==2)
{
int x,y;
cin>>x>>y;
cout<<(qpath(x,y)%p+p)%p<<'\n';
}
if(op==3)
{
int x,z;
cin>>x>>z;
mtr(x,z);
}
if(op==4)
{
int x;
cin>>x;
cout<<(qtr(x)%p+p)%p<<'\n';
}
}
return 0;
}