#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7;
int n,m,rr,p;
int w[N];
vector<int>G[N];
int dep[N];
int fa[N];
int siz[N];
int hson[N];
int top[N];
int dfn[N],tot;
int rnk[N];
int T[N*4];
int lzy[N*4];
int End[N];
int x,y,z;
void dfs1(int u,int pa,int d)
{
fa[u]=pa;
dep[u]=d;
siz[u]=1;
int cnnt=0;
hson[u]=-1;
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i];
if(v==pa)continue;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[v]>cnnt)
{
cnnt=siz[v];
hson[u]=v;
}
}
}
void dfs2(int u,int Top)
{
top[u]=Top;
dfn[u]=++tot;
rnk[tot]=u;
if(hson[u]==-1)return;
dfs2(hson[u],Top);
End[hson[u]]=tot;
for(int i=0;i<G[u].size();++i)
{
int v=G[u][i];
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);
End[v]=tot;
}
}
void build_tree(int u,int l,int r)
{
if(l==r)
{
T[u]=w[rnk[l]]%p;
return;
}
int mid=(l+r)/2;
build_tree(u*2,l,mid);
build_tree(u*2+1,mid+1,r);
T[u]=(T[u*2]+T[u*2+1])%p;
}
void pushdown(int u,int l,int r,int mid)
{
lzy[u*2]=(lzy[u*2]+lzy[u])%p;T[u*2]=(T[u*2]+(lzy[u]*(mid-l+1))%p)%p;
lzy[u*2+1]=(lzy[u*2+1]+lzy[u])%p;T[u*2+1]=(T[u*2+1]+(lzy[u]*(r-mid))%p)%p;
lzy[u]=0;
return;
}
void update(int u,int l,int r,int L,int R,int pos)
{
if(l>=L&&r<=R)
{
lzy[u]=(lzy[u]+pos)%p;
T[u]=(T[u]+(pos*(r-l+1))%p)%p;
return;
}
int mid=(l+r)/2;
pushdown(u,l,r,mid);
if(L<=mid)update(u*2,l,mid,L,R,pos);
if(R>mid)update(u*2+1,mid+1,r,L,R,pos);
}
int query(int u,int l,int r,int L,int R)
{
int cnt=0;
if(l>=L&&r<=R)
{
cnt=(cnt+T[u])%p;
return cnt;
}
int mid=(l+r)/2;
pushdown(u,l,r,mid);
if(L<=mid)cnt=(cnt+query(u*2,l,mid,L,R))%p;
if(R>mid)cnt=(cnt+query(u*2+1,mid+1,r,L,R))%p;
return cnt;
}
void op1()
{
scanf("%lld%lld%lld",&x,&y,&z);
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}
update(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),z);
return;
}
void op2()
{
scanf("%lld%lld",&x,&y);
int TOT=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
TOT=(TOT+query(1,1,n,dfn[top[x]],dfn[x]))%p;
x=fa[top[x]];
}
TOT=(TOT+query(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y])))%p;
printf("%lld\n",TOT);
return;
}
void op3()
{
scanf("%lld%lld",&x,&z);
update(1,1,n,dfn[x],End[x],z);
return;
}
void op4()
{
scanf("%lld",&x);
int TOT=query(1,1,n,dfn[x],End[x])%p;
printf("%lld\n",TOT);
return;
}
signed main()
{
scanf("%lld%lld%lld%lld",&n,&m,&rr,&p);
for(int i=1;i<=n;++i)
scanf("%lld",&w[i]);
for(int i=1;i<n;++i)
{
int u,v;
scanf("%lld%lld",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(rr,rr,1);
dfs2(rr,rr);
build_tree(1,1,n);
End[rr]=n;
while(m--)
{
int op;
scanf("%lld",&op);
if(op==1)op1();
if(op==2)op2();
if(op==3)op3();
if(op==4)op4();
}
return 0;
}