#include<stdio.h>
#define ll long long
#define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout);
const int N=1e5;
int n,m,r,P,id[N+1];
inline int Min(int a,int b){return a<b?a:b;}
inline int Max(int a,int b){return a>b?a:b;}
inline void Swap(int &a,int &b){int t=a;a=b;b=t;}
int head[N+1],num_edge;
struct Gragh{
int to,next;
}edge[2*(N)];
void Add_edge(int from,int to) {edge[++num_edge]=(Gragh){to,head[from]};head[from]=num_edge;}
struct Node{
int d,fa,sz,bs,t,top,w;
}p[N+1];
void Dfs1(int u,int fa,int deep)
{
p[u].fa=fa,p[u].d=deep,p[u].sz=1;
for(int i=head[u];i;i=edge[i].next)
{
if(edge[i].to!=fa)
{
Dfs1(edge[i].to,u,deep+1);
p[u].sz+=p[edge[i].to].sz;
if(p[edge[i].to].sz>p[p[u].bs].sz)
p[u].bs=edge[i].to;
}
}
}
int index_t;
void Dfs2(int u,int top)
{
p[u].t=++index_t,p[u].top=top;
id[index_t]=u;
if(!p[u].bs) return ;
Dfs2(p[u].bs,top);
for(int i=head[u];i;i=edge[i].next)
{
if(edge[i].to!=p[u].fa&&edge[i].to!=p[u].bs)
{
Dfs2(edge[i].to,edge[i].to);
}
}
}
struct Seg{
int l,r,sum,add;
}t[4*(N+1)];
struct Ope{
int l,r,w;
}modify,getsum;
void Build(int k,int l,int r)
{
t[k].l=l,t[k].r=r;
if(l==r)
{
t[k].sum=p[id[l]].w;
return ;
}
int mid=(l+r)>>1;
Build(k<<1,l,mid);
Build(k<<1|1,mid+1,r);
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
void Modify(int k)
{
if(t[k].l>modify.r||t[k].r<modify.l) return ;
if(t[k].l>=modify.l&&t[k].r<=modify.r)
{
t[k].add+=modify.w;
return;
}
t[k].sum+=(Min(t[k].r,modify.r)-Max(t[k].l,modify.l)+1)*modify.w;
int mid=(t[k].l+t[k].r)>>1;
if(modify.l<=mid) Modify(k<<1);
if(modify.r>mid) Modify(k<<1|1);
}
ll Getsum(int k)
{
if(getsum.l>t[k].r||getsum.r<t[k].l) return 0;
if(t[k].l>=getsum.l&&t[k].r<=getsum.r)
{
return (t[k].sum+((t[k].r-t[k].l+1)*t[k].add)%P)%P;
}
int mid=(t[k].l+t[k].r)>>1;
ll res=((Min(t[k].r,getsum.r)-Max(t[k].l,getsum.l)+1)*t[k].add)%P;
//通货是没有传递下去的,没有必要
if(getsum.l<=mid) res=(res+Getsum(k<<1))%P;
if(getsum.r>mid) res=(res+Getsum(k<<1|1))%P;
return res;
}
void Modify_path(int l,int r,ll w)
{
while(p[l].top!=p[r].top)
{
if(p[l].d<p[r].d) Swap(l,r);
modify=(Ope){p[p[l].top].t,p[l].t,w},Modify(1);
l=p[p[l].top].fa;
}
if(p[l].d>p[r].d) Swap(l,r);
modify=(Ope){p[l].t,p[r].t,w},Modify(1);
}
inline ll Getsum_path(int l,int r)
{
ll res=0;
while(p[l].top!=p[r].top)
{
if(p[l].d<p[r].d) Swap(l,r);
getsum=(Ope){p[p[l].top].t,p[l].t},res=(res+Getsum(1))%P;
l=p[p[l].top].fa;
}
if(p[l].d>p[r].d) Swap(l,r);
getsum=(Ope){p[l].t,p[r].t},res=(res+Getsum(1))%P;
return res;
}
void Modify_subtree(int u,int w)
{
modify=(Ope){p[u].t,p[u].t+p[u].sz-1,w},Modify(1);
}
inline ll Getsum_subtree(int u)
{
getsum=(Ope){p[u].t,p[u].t+p[u].sz-1};return Getsum(1);
}
int main()
{
//File("1");
scanf("%d%d%d%d",&n,&m,&r,&P);
ll fw;
for(int i=1;i<=n;i++) scanf("%lld",&fw),p[i].w=fw%P;
int from,to;
for(int i=1;i<n;i++)
{
scanf("%d%d",&from,&to);
Add_edge(from,to),Add_edge(to,from);
}
Dfs1(r,0,1);
Dfs2(r,r);
int ty,l,r,w,tree;
Build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d",&ty);
if(ty==1)
{
scanf("%d%d%lld",&l,&r,&w);
Modify_path(l,r,w%P);
}
else if(ty==2)
{
scanf("%d%d",&l,&r);
printf("%d\n",Getsum_path(l,r));
}
else if(ty==3)
{
scanf("%d%lld",&l,&w);
Modify_subtree(l,w%P);
}
else
{
scanf("%d",&l);
printf("%d\n",Getsum_subtree(l));
}
}
return 0;
}