#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const ll N=1e6+10;
ll n,m,r,M;
ll a[N];
vector<ll> edge[N];
ll fa[N],deep[N],siz[N],top[N],to[N],from[N],son[N],dfn[N];
ll cnt=0;
void dfs1(ll x,ll f)
{
siz[x]=1;
fa[x]=f;
deep[x]=deep[f]+1;
for(ll i=0;i<edge[x].size();i++)
{
ll t=edge[x][i];
if(t==f) continue;
dfs1(t,x);
siz[x]+=siz[t];
if(siz[son[x]]<siz[t]) son[x]=t;
}
}
void dfs2(ll x,ll f,ll tp)
{
cnt++;
to[x]=cnt;
from[cnt]=x;
top[x]=tp;
if(son[x]) dfs2(son[x],x,tp);
for(ll i=0;i<edge[x].size();i++)
{
ll t=edge[x][i];
if(t==f) continue;
if(t==son[x]) continue;
dfs2(t,x,t);
}
dfn[x]=cnt;
}
ll tree[N*4];
ll lazy[N*4];
void pushup(ll p,ll l,ll r)
{
tree[p]=tree[p*2]+tree[p*2+1];
tree[p]%=M;tree[p*2]%=M;tree[p*2+1]%=M;
}
void pushdown(ll p,ll l,ll r)
{
ll mid=(l+r)/2;
lazy[p*2]+=lazy[p]; lazy[p*2+1]+=lazy[p];
tree[p*2]+=lazy[p]*(mid-l+1);
tree[p*2+1]+=lazy[p]*(r-mid);
lazy[p]=0;
pushup(p,l,r);
}
void build(ll p,ll l,ll r)
{
if(l==r)
{
tree[p]=a[from[l]]%M;
return ;
}
ll mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p,l,r);
}
void add1(ll p,ll l,ll r,ll x,ll z)
{
if(l==r)
{
tree[p]+=z;
tree[p]%=M;
return ;
}
if(lazy[p]) pushdown(p,l,r);
ll mid=(l+r)/2;
if(x<=mid) add1(p*2,l,mid,x,z);
else add1(p*2+1,mid+1,r,x,z);
pushup(p,l,r);
}
void add2(ll p,ll l,ll r,ll x,ll y,ll z)
{
if(x<=l&&r<=y)
{
tree[p]+=z*(r-l+1);
lazy[p]+=z;
tree[p]%=M;
return ;
}
if(lazy[p]) pushdown(p,l,r);
ll mid=(l+r)/2;
if(x<=mid) add2(p*2,l,mid,x,y,z);
if(y>=mid+1) add2(p*2+1,mid+1,r,x,y,z);
pushup(p,l,r);
}
ll cala(ll p,ll l,ll r,ll x,ll y)
{
if(x<=l&&r<=y)
{
return tree[p];
}
if(lazy[p]) pushdown(p,l,r);
ll mid=(l+r)/2;
ll ans=0;
if(x<=mid) ans+=cala(p*2,l,mid,x,y);
if(y>=mid+1) ans+=cala(p*2+1,mid+1,r,x,y);
return ans%M;
}
void add_lca(ll x,ll y,ll z)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
add2(1,1,n,to[x],to[top[x]],z);
x=fa[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
add2(1,1,n,to[x],to[y],z);
}
ll cala_lca(ll x,ll y)
{
ll ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=cala(1,1,n,to[x],to[top[x]]);
ans%=M;
x=fa[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
ans+=cala(1,1,n,to[x],to[y]);
return ans%M;
}
int main()
{
cin>>n>>m>>r>>M;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
}
for(ll i=1;i<n;i++)
{
ll x,y;
cin>>x>>y;
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs1(r,0);
dfs2(r,0,r);
build(1,1,n);
for(ll i=1;i<=m;i++)
{
ll opt;
cin>>opt;
if(opt==1)
{
ll x,y,z;
cin>>x>>y>>z;
add_lca(x,y,z);
}
else if(opt==2)
{
ll x,y;
cin>>x>>y;
cout<<cala_lca(x,y)<<endl;
}
else if(opt==3)
{
ll x,z;
cin>>x>>z;
add2(1,1,n,to[x],dfn[x],z);
}
else if(opt==4)
{
ll x;
cin>>x;
cout<<cala(1,1,n,to[x],dfn[x])<<endl;
}
}
return 0;
}