#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn=100005;
ll n,m,r,p;
ll d[maxn];
struct node
{
ll next,to,w;
}e[200005];
struct NODE
{
ll l,r,val,add;
}tree[400005];
ll rp,tot;
ll head[200005],cnt;
ll fa[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],dfn[maxn],rnk[maxn];
void add(ll u,ll v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(ll u,ll f,ll w)
{
fa[u]=f;
son[u]=-1;
siz[u]=1;
dep[u]=w;//更新节点u深度
for(int i=head[u];i!=-1;i=e[i].next)
{
ll v=e[i].to;
if(v==f){continue;}
dfs(v,u,w+1);
siz[u]+=siz[v];//更新节点u的子树的节点个数
if(son[u]==-1||siz[son[u]]<siz[son[v]]){son[u]=v;}//更新重儿子
}
}
void dfs2(ll u,ll tt)
{
top[u]=tt;
++tot;
dfn[u]=tot;
rnk[tot]=u;
if(son[u]==-1){return;}
dfs2(son[u],tt);
for(int i=head[u];i!=-1;i=e[i].next)
{
ll v=e[i].to;
if(v==fa[u]){continue;}
if(v!=son[u])
{dfs2(v,v);}
}
}
void build(ll os,ll l,ll r)
{
tree[os].l=l;
tree[os].r=r;
if(l==r)
{
tree[os].val=d[rnk[++rp]]%p;
return;
}
ll mid=(l+r)/2;
build(os*2,l,mid);
build(os*2+1,mid+1,r);
tree[os].val=(tree[os*2].val+tree[os*2+1].val)%p;
}
void spread(ll os)
{
if(tree[os].add)
{
tree[os*2].val=(tree[os*2].val+(((tree[os*2].r-tree[os*2].l+1)%p)*(tree[os].add)%p)%p)%p;
tree[os*2+1].val=(tree[os*2+1].val+(((tree[os*2+1].r-tree[os*2+1].l+1)%p)*(tree[os].add)%p)%p)%p;
tree[os*2].add=(tree[os*2].add+tree[os].add)%p;
tree[os*2+1].add=(tree[os*2+1].add+tree[os].add)%p;
tree[os].add=0;
}
}
void change(ll os,ll x,ll y,ll z)
{
if(x<=tree[os].l&&y>=tree[os].r)
{
tree[os].val=(tree[os].val+(((tree[os].r-tree[os].l+1)%p)*z%p)%p)%p;
tree[os].add=(tree[os].add+z)%p;
return;
}
spread(os);
ll mid=(tree[os].l+tree[os].r)/2;
if(x<=mid)
{change(os*2,x,y,z%p);}
if(y>mid)
{change(os*2+1,x,y,z%p);}
tree[os].val=(tree[os*2].val+tree[os*2+1].val)%p;
}
ll query(ll os,ll x,ll y)
{
if(x<=tree[os].l&&y>=tree[os].r)
{return tree[os].val;}
spread(os);
ll mid=(tree[os].l+tree[os].r)/2;
ll ans=0;
if(x<=mid)
{ans=(ans+query(os*2,x,y))%p;}
if(y>mid)
{ans=(ans+query(os*2+1,x,y))%p;}
return ans%p;
}
void solvec(ll x,ll y,ll z)
{
ll sx=top[x],sy=top[y];
while(sx!=sy)
{
if(dep[sx]>=dep[sy])
{
change(1,dfn[sx],dfn[x],z%p);
x=fa[sx];
sx=top[x];
}
else
{
change(1,dfn[sy],dfn[y],z%p);
y=fa[sy];
sy=top[y];
}
}
if(dfn[x]<=dfn[y])
{change(1,dfn[x],dfn[y],z%p);}
else
{change(1,dfn[y],dfn[x],z%p);}
}
ll solveq(ll x,ll y)
{
ll ans=0;
ll sx=top[x],sy=top[y];
while(sx!=sy)
{
if(dep[sx]>=dep[sy])
{
ans=(ans+query(1,dfn[sx],dfn[x]))%p;
x=fa[sx];
sx=top[x];
}
else
{
ans=(ans+query(1,dfn[sy],dfn[y]))%p;
y=fa[sy];
sy=top[y];
}
}
if(dfs[x]<=dfs[y])
{ans=(ans+query(1,dfn[x],dfn[y]))%p;}
else
{ans=(ans+query(1,dfn[y],dfn[x]))%p;}
return ans;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%lld %lld %lld %lld",&n,&m,&r,&p);
for(int i=1;i<=n;i++){scanf("%lld",&d[i]);}
for(int i=1;i<=n-1;i++)
{
ll x,y;
scanf("%lld %lld",&x,&y);
add(x,y);
add(y,x);
}
dfs(r,r,1);
dfs2(r,r);
build(1,1,n);
while(m--)
{
ll x,y,z,op;
scanf("%lld",&op);
if(op==1)
{
scanf("%lld %lld %lld",&x,&y,&z);
solvec(x,y,z);
}
if(op==2)
{
scanf("%lld %lld",&x,&y);
printf("%lld\n",solveq(x,y));
}
if(op==3)
{
scanf("%lld %lld",&x,&z);
change(1,dfn[x],dfn[x]+siz[x]-1,z%p);
}
if(op==4)
{
scanf("%lld",&x);
printf("%lld\n",query(1,dfn[x],dfn[x]+siz[x]-1));
}
}
return 0;
}
救救孩子