#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=300005;
struct edge
{
long long to;
long long nxt;
long long w,wt;
}e[maxn*2];
struct tree
{
long long l,r;
long long add,pre;
}t[maxn*4];
long long cnt,n,m,r,p,df;
long long head[maxn*4];
long long son[maxn*2],deep[maxn*2],fa[maxn*2],siz[maxn*2],dfn[maxn*2],top[maxn*2];
void addedge(long long u,long long v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void build(long long i,long long l,long long r)
{
t[i].l=l,t[i].r=r;
if(l==r)
{
t[i].pre=e[l].wt;
return;
}
long long mid=l+r>>1;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
t[i].pre=(t[i*2].pre+t[i*2+1].pre)%p;
}
void push_down(long long i)
{
if(t[i].add)
{
t[i*2].pre+=t[i].add*(t[i*2].r-t[i*2].l+1)%p;
t[i*2+1].pre+=t[i].add*(t[i*2+1].r-t[i*2+1].l+1)%p;
t[i*2].add+=t[i].add;
t[i*2+1].add+=t[i].add;
t[i].add=0;
}
}
void updata(long long i,long long l,long long r,long long m)
{
if(t[i].l>=l&&t[i].r<=r)
{
t[i].pre+=m*(t[i].r-t[i].l+1)%p;
t[i].add+=m;
return;
}
push_down(i);
long long mid=t[i].l+t[i].r>>1;
if(l<=mid)updata(i*2,l,r,m);
if(r>mid)updata(i*2+1,l,r,m);
t[i].pre=(t[i*2].pre+t[i*2+1].pre)%p;
}
long long query(long long i,long long l,long long r)
{
if(t[i].l>=l&&t[i].r<=r)
{
return t[i].pre;
}
push_down(i);
long long mid=t[i].l+t[i].r>>1;
long long ans=0;
if(l<=mid)ans=(ans+query(i*2,l,r))%p;
if(r>mid)ans=(ans+query(i*2+1,l,r))%p;
return ans%p;
}
void dfs1(long long x,long long f,long long len)
{
deep[x]=len;
fa[x]=f;
siz[x]=1;
for(long long i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==f)continue;
dfs1(y,x,len+1);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]])
{
son[x]=y;
}
}
}
void dfs2(long long x,long long tp)
{
top[x]=tp;
dfn[x]=++df;
e[df].wt=e[x].w;
if(!son[x])return;
dfs2(son[x],tp);
for(long long i=head[x];i;i=e[i].nxt)
{
long long y=e[i].to;
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);
}
}
void tree_add(long long x,long long y,long long val)
{
while(top[x]!=top[y])
{
if(deep[x]<deep[y])swap(x,y);
updata(1,dfn[top[x]],dfn[x],val);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
updata(1,dfn[x],dfn[y],val);
}
void tree_check(long long x,long long y)
{
long long ans=0;
while(top[x]!=top[y])
{
if(deep[x]<deep[y])swap(x,y);
ans=(ans+query(1,dfn[top[x]],dfn[x]))%p;
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
ans=(ans+query(1,dfn[x],dfn[y]))%p;
cout<<ans%p<<endl;
}
int main()
{
cin>>n>>m>>r>>p;
for(long long i=1;i<=n;i++)
{
cin>>e[i].w;
e[i].w%=p;
}
for(long long i=1;i<n;i++)
{
long long a,b;
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
for(long long i=1;i<=m;i++)
{
long long f,x,y,z;
cin>>f>>x;
if(f==1)
{
cin>>y>>z;
tree_add(x,y,z);
}
if(f==2)
{
cin>>y;
tree_check(x,y);
}
if(f==3)
{
cin>>z;
updata(1,dfn[x],dfn[x]+siz[x]-1,z);
}
if(f==4)
{
cout<<query(1,dfn[x],dfn[x]+siz[x]-1)%p<<endl;
}
}
}