#include<iostream>
#include<stdio.h>
#define int long long
using namespace std;
int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+f*(c-'0'),c=getchar();
return x;
}
const int MAXN=1e5+10;
int n,m,root,HgS;
int u[MAXN*2],v[MAXN*2],first[2*MAXN],net[MAXN*2];
int g[MAXN];
int cnt=0;
int size[MAXN];
int d[MAXN];
struct node
{
int t,v,b,f;
int dep;
}a[MAXN];
int shu[MAXN*8],lazy[MAXN*8];
int tot=0;
void ycl()
{
for(int i=1;i<=n;i++)
first[i]=-1;
}
void newnode(int t,int b,int f,int dep)
{
tot++;
a[tot].t=t;
a[tot].v=g[t];
a[tot].b=b;
a[tot].f=f;
a[tot].dep=dep;
d[t]=tot;
}
void add(int x,int y)
{
u[++cnt]=x;
v[cnt]=y;
net[cnt]=first[x];
first[x]=cnt;
}
int dfs1(int x,int last)
{
int ans=1;
for(int i=first[x];i!=-1;i=net[i])
{
if(v[i]==last)continue;
ans=(ans+dfs1(v[i],x))%HgS;
}
size[x]=ans;
return ans;
}
void dfs2(int x,int last,int y,int sum)
{
int h=0,maxn=-1;
for(int i=first[x];i!=-1;i=net[i])
{
if(v[i]==last)continue;
if(size[v[i]]>maxn)
{
h=v[i];
maxn=size[v[i]];
}
}
if(h==0)return ;
newnode(h,y,x,sum+1);
dfs2(h,x,y,sum+1);
for(int i=first[x];i!=-1;i=net[i])
{
if(v[i]==last)continue;
if(v[i]==h)continue;
newnode(v[i],v[i],x,sum+1);
dfs2(v[i],x,v[i],sum+1);
}
return ;
}
void update(int x)
{
shu[x]=(shu[x*2]+shu[x*2+1])%HgS;
return ;
}
void pushdown(int x,int l,int r)
{
int mid=(l+r)>>1;
shu[x*2]=(shu[x*2]+lazy[x]*(mid-l+1))%HgS;
lazy[x*2]=(lazy[x*2]+lazy[x])%HgS;
shu[2*x+1]=(shu[2*x+1]+lazy[x]*(r-mid))%HgS;
lazy[2*x+1]=(lazy[2*x+1]+lazy[x])%HgS;
lazy[x]=0;
}
void build(int now,int l,int r)
{
if(l==r)
{
shu[now]=a[l].v;
return ;
}
int mid=(l+r)>>1;
build(now*2,l,mid);
build(now*2+1,mid+1,r);
update(now);
}
void add2(int now,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y)
{
shu[now]=(shu[now]+(r-l+1)*v)%HgS;
lazy[now]=(lazy[now]+v)%HgS;
return ;
}
pushdown(now,l,r);
int mid=(l+r)>>1;
if(mid>=x)add2(now*2,l,mid,x,y,v);
if(mid+1<=y)add2(now*2+1,mid+1,r,x,y,v);
update(now);
}
int getsum(int now,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
{
return shu[now];
}
pushdown(now,l,r);
int mid=(l+r)>>1;
int ans=0;
if(mid>=x)ans=(ans+getsum(now*2,l,mid,x,y))%HgS;
if(mid+1<=y)ans=(ans+getsum(now*2+1,mid+1,r,x,y))%HgS;
return ans%HgS;
}
void increase(int x,int y,int z)
{
while(true)
{
if(a[d[a[d[x]].b]].dep>a[d[a[d[y]].b]].dep)
{
add2(1,1,n,d[a[d[x]].b],d[x],z);
x=a[d[a[d[x]].b]].f;
}
else if(a[d[x]].b==a[d[y]].b){
if(d[x]>d[y])swap(x,y);
add2(1,1,n,d[x],d[y],z);
break;
}
else
{
add2(1,1,n,d[a[d[y]].b],d[y],z);
y=a[d[a[d[y]].b]].f;
}
}
}
int query1(int x,int y)
{
int ans=0;
while(true)
{
if(a[d[a[d[x]].b]].dep>a[d[a[d[y]].b]].dep)
{
ans=(ans+getsum(1,1,n,d[a[d[x]].b],d[x]))%HgS;
x=a[d[a[d[x]].b]].f;
}
else if(a[d[x]].b==a[d[y]].b)
{
if(d[x]>d[y])swap(x,y);
ans=(ans+getsum(1,1,n,d[x],d[y]))%HgS;
return ans;
}
else
{
ans=(ans+getsum(1,1,n,d[a[d[y]].b],d[y]))%HgS;
y=a[d[a[d[y]].b]].f;
}
}
}
signed main()
{
n=read();
m=read();
root=read();
HgS=read();
ycl();
for(int i=1;i<=n;i++)
g[i]=read()%HgS;
for(int i=1;i<n;i++)
{
int x,y;
x=read();
y=read();
add(x,y);
add(y,x);
}
size[root]=dfs1(root,0);
newnode(root,root,0,1);
dfs2(root,0,root,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int opt;
opt=read();
if(opt==1)
{
int x,y,z;
x=read();
y=read();
z=read()%HgS;
increase(x,y,z);
}
else if(opt==2)
{
int x,y;
x=read();
y=read();
printf("%lld\n",query1(x,y)%HgS);
}
else if(opt==3)
{
int x,z;
x=read();
z=read()%HgS;
add2(1,1,n,d[x],d[x]+size[x]-1,z);
}
else if(opt==4)
{
int x;
x=read();
printf("%lld\n",getsum(1,1,n,d[x],d[x]+size[x]-1)%HgS);
}
}
return 0;
}