/*
洛谷3384
1、 树剖板子题
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<queue>
using namespace std;
#define ll long long
const int cnt=2e5+5;
int stati;
int p,n;
int deep[cnt],siz[cnt],fa[cnt],son[cnt],topp[cnt],id[cnt],reid[cnt],a[cnt];
vector<int>mp[cnt];
int tree[4*cnt],flag[4*cnt];
void dfs1(int x,int f,int dp)
{
int i;
deep[x]=dp;
fa[x]=f;
siz[x]=1;
int maxn=-1;
for(i=0;i<mp[x].size();i++)
{
if(mp[x][i]!=f)
{
dfs1(mp[x][i],x,dp+1);
siz[x]+=siz[mp[x][i]];
if(siz[mp[x][i]]>maxn)
{
son[x]=mp[x][i];
maxn=siz[mp[x][i]];
}
}
}
}
void dfs2(int x,int topf)
{
int i;
id[x]=stati++;
reid[stati-1]=x;
topp[x]=topf;
if(!son[x])return;
dfs2(son[x],topf);
for(i=0;i<mp[x].size();i++)
{
int y=mp[x][i];
if(y!=son[x]&&y!=fa[x])
{
dfs2(y,y);
}
}
}
void build(int L,int R,int num)
{
tree[num]=0;
flag[num]=0;
if(L==R)
{
tree[num]=a[reid[L]]%p;
return ;
}
int mid=(L+R)/2;
build(L,mid,num*2);
build(mid+1,R,num*2+1);
tree[num]=(tree[num*2]+tree[num*2+1])%p;
}
void pushdown(int le,int ri,int num)
{
int mid=(le+ri)/2;
if(flag[num])
{
tree[num*2]=(tree[num*2]+flag[num]*(mid-le+1))%p;
tree[num*2+1]=(tree[num*2+1]+flag[num]*(ri-mid))%p;
flag[num*2]+=flag[num];
flag[num*2+1]+=flag[num];
flag[num]=0;
}
}
void pushup(int num)
{
tree[num]=(tree[num*2]+tree[num*2+1])%p;
}
void update(int L,int R,int le,int ri,int num,int c)
{
c%=p;
if(L<=le&&R>=ri)
{
tree[num]=(tree[num]+c*(ri-le+1))%p;
flag[num]+=c;
return;
}
pushdown(le,ri,num);
int mid=(le+ri)/2;
if(L<=mid)update(L,R,le,mid,num*2,c);
if(R>mid)update(L,R,mid+1,ri,num*2+1,c);
pushup(num);
}
void upupdate(int L,int R,int c)
{
c%=p;
int x=L;
int y=R;
while(topp[x]!=topp[y])
{
if(deep[topp[x]]<deep[topp[y]])
swap(x,y);
update(id[topp[x]],id[x],1,n,1,c);
x=fa[topp[x]];
}
if(deep[x]>deep[y])
swap(x,y);
update(id[x],id[y],1,n,1,c);
}
int query(int L,int R,int le,int ri,int num)
{
int ans=0;
if(L<=le&&R>=ri)
{
return tree[num]%p;
}
pushdown(le,ri,num);
int mid=(le+ri)/2;
if(L<=mid)ans=(ans+query(L,R,le,mid,num*2))%p;
if(R>mid)ans=(ans+query(L,R,mid+1,ri,num*2+1))%p;
return ans;
}
int Uquery(int L,int R)
{
int ans=0;
int x=L,y=R;
while(topp[x]!=topp[y])
{
if(deep[topp[x]]<deep[topp[y]])
{
swap(x,y);
}
ans=(ans+query(id[topp[x]],id[x],1,n,1))%p;
x=fa[topp[x]];
}
if(deep[x]>deep[y])
swap(x,y);
ans=(ans+query(id[x],id[y],1,n,1))%p;
return ans;
}
int main()
{
// std::ios::sync_with_stdio(false);
int m,r,i,x,y,op,z;
memset(son,0,sizeof(son));
scanf("%d %d %d %d",&n,&m,&r,&p);
stati=1;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]%=p;
}
for(i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
dfs1(r,-1,1);
dfs2(r,r);
build(1,n,1);
for(i=0;i<m;i++)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d %d %d",&x,&y,&z);
upupdate(x,y,z);
}
else if(op==2)
{
scanf("%d %d",&x,&y);
printf("%d\n",Uquery(x,y));
}
else if(op==3)
{
scanf("%d %d",&x,&z);
update(id[x],id[x]+siz[x]-1,1,n,1,z);
}
else
{
scanf("%d",&x);
printf("%d\n",query(id[x],id[x]+siz[x]-1,1,n,1));
}
}
return 0;
}