#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int cnt,time,head[N],w[N],dep[N],size[N],fa[N],son[N],dfn[N],rnk[N],top[N];
struct Edge{int next,to;}g[N<<1];
void add(int u,int v)
{
g[++cnt]=(Edge){head[u],v};
head[u]=cnt;
}
int n,m,MOD,root;
#define ls x<<1
#define rs x<<1|1
int ty[N<<2],d[N<<2];
inline void build(int x,int l,int r)
{
if(l==r)
{
ty[x]=rnk[l]%MOD;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
ty[x]=(ty[ls]+ty[rs])%MOD;
}
inline void pushdown(int x,int l,int r,int mid)
{
if(!d[x]) return;
d[ls]+=d[x],d[rs]+=d[x];
ty[ls]+=(mid-l+1)*d[x];
ty[rs]+=(r-mid)*d[x];
d[x]=0;
}
inline int query(int x,int l,int r,int ql,int qr)
{
if(ql>r||qr<l) return 0;
if(ql<=l&&r<=qr) return ty[x];
int mid=(l+r)>>1;
pushdown(x,l,r,mid);
return query(ls,l,mid,ql,qr)+query(rs,mid+1,r,ql,qr);
}
inline void update(int x,int l,int r,int ql,int qr,int y)
{
if(ql>r||qr<l) return;
if(ql<=l&&r<=qr)
{
ty[x]=(ty[x]+(r-l+1)*y)%MOD,d[x]=y;
return;
}
int mid=(l+r)>>1;
pushdown(x,l,r,mid);
update(ls,l,mid,ql,qr,y);
update(rs,mid+1,r,ql,qr,y);
ty[x]=(ty[ls]+ty[rs])%MOD;
}
int first_query(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=(ans+query(1,1,n,dfn[top[x]],dfn[x]))%MOD;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,dfn[x],dfn[y])%MOD;
return ans;
}
int second_query(int x)
{
return query(1,1,n,dfn[x],dfn[x]+size[x]-1);
}
void first_update(int x,int y,int k)
{
k%=MOD;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,dfn[x],dfn[y],k);
}
void second_update(int x,int k)
{
update(1,1,n,dfn[x],dfn[x]+size[x]-1,k);
}
inline 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*10+c-'0',c=getchar();
return x*f;
}
inline void dfs1(int x,int f,int deep)
{
dep[x]=deep,fa[x]=f,size[x]=1;
int maxson=-1;
for(int i=head[x];i;i=g[i].next)
{
int v=g[i].to;if(v==f) continue;
dfs1(v,x,deep+1);
size[x]+=size[v];
if(maxson<size[v])maxson=size[v],son[x]=v;
}
}
inline void dfs2(int x,int topp)
{
top[x]=topp;dfn[x]=++time;rnk[time]=w[x];
if(!son[x]) return;
dfs2(son[x],topp);
for(int i=head[x];i;i=g[i].next)
if(g[i].to!=son[x]&&g[i].to!=fa[x])dfs2(g[i].to,g[i].to);
}
int main()
{
n=read(),m=read(),root=read(),MOD=read();
for(int i=1;i<=n;i++) w[i]=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(root,0,1);
dfs2(root,root);
while(m--)
{
int op=read();
if(op==1)
{
int x=read(),y=read(),z=read();
first_update(x,y,z);
}
else if(op==2)
{
int x=read(),z=read();
second_update(x,z);
}
else if(op==3)
{
int x=read(),y=read();
printf("%d\n",first_query(x,y));
}
else
{
int x=read();
printf("%d\n",second_query(x));
}
}
return 0;
}