#include<iostream>
#include<vector>
using namespace std;
const int MAXN=1234567;
long long n,m,r,p,cnt;
long long op,x,y,z;
vector<int> G[MAXN];
long long a[MAXN],f[MAXN],d[MAXN],sz[MAXN],hs[MAXN],tp[MAXN],dfn[MAXN],rk[MAXN],vis[MAXN],bt[MAXN],t[4*MAXN],tag[4*MAXN];
void pushup(int id)
{
t[id]=t[id*2]+t[id*2+1];
t[id]%=p;
}
void fc(int id,int l,int r,long long k)
{
t[id]+=(r-l+1)*k;
t[id]%=p;
tag[id]+=k;
tag[id]%=p;
}
void pushdown(int id,int l,int r)
{
int mid=(l+r)/2;
fc(id*2,l,mid,tag[id]);
fc(id*2+1,mid+1,r,tag[id]);
tag[id]=0;
}
void build_tree(int id,int l,int r)
{
if(l==r)
{
t[id]=a[rk[l]];
return;
}
int mid=(l+r)/2;
build_tree(id*2,l,mid);
build_tree(id*2+1,mid+1,r);
pushup(id);
}
void update(int id,int l,int r,int x,int y,long long k)
{
if(x<=l&&r<=y)
{
fc(id,l,r,k);
return;
}
pushdown(id,l,r);
int mid=(l+r)/2;
if(x<=mid)
{
update(id*2,l,mid,x,y,k);
}
if(y>mid)
{
update(id*2+1,mid+1,r,x,y,k);
}
pushup(id);
}
long long query(int id,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
{
return t[id]%p;
}
pushdown(id,l,r);
int mid=(l+r)/2;
long long ans=0;
if(x<=mid)
{
ans+=query(id*2,l,mid,x,y);
ans%=p;
}
if(y>mid)
{
ans+=query(id*2+1,mid+1,r,x,y);
ans%=p;
}
return ans;
}
void upd(int x,int y,long long k)
{
update(1,1,n,x,y,k);
}
long long qry(int x,int y)
{
return query(1,1,n,x,y);
}
long long build(int u,int dep)
{
int hsz=0;
hs[u]=0;
d[u]=dep;
sz[u]=1;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(vis[v])
{
continue;
}
vis[v]=1;
sz[u]+=build(v,dep+1);
f[v]=u;
if(sz[v]>hsz)
{
hs[u]=v;
hsz=sz[v];
}
}
return sz[u];
}
void dfs(int u,int top)
{
tp[u]=top;
cnt++;
dfn[u]=cnt;
rk[cnt]=u;
bt[u]=dfn[u];
if(hs[u])
{
if(!vis[hs[u]])
{
vis[hs[u]]=1;
dfs(hs[u],top);
}
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(vis[v])
{
continue;
}
vis[v]=1;
if(v!=hs[u])
{
dfs(v,v);
}
bt[u]=max(bt[u],bt[v]);
}
}
}
void path_add(int u,int v,int k)
{
while(tp[u]!=tp[v])
{
if(d[tp[u]]<d[tp[v]])
{
swap(u,v);
}
upd(dfn[u],dfn[tp[u]],k);
u=f[tp[u]];
}
upd(dfn[u],dfn[v],k);
}
long long path_sum(int u,int v)
{
long long ans=0;
while(tp[u]!=tp[v])
{
if(d[tp[u]]<d[tp[v]])
{
swap(u,v);
}
ans+=qry(dfn[u],dfn[tp[u]])%p;
u=f[tp[u]];
}
ans+=qry(dfn[u],dfn[v])%p;
return ans%p;
}
int main()
{
//freopen("in.txt","r",stdin);
cin>>n>>m>>r>>p;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[i]%=p;
}
for(int i=1;i<n;i++)
{
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
vis[r]=1;
build(r,1);
for(int i=1;i<=n;i++)
{
vis[i]=0;
}
vis[r]=1;
dfs(r,r);
build_tree(1,1,n);
for(int i=1;i<=m;i++)
{
cin>>op>>x;
if(op==1)
{
cin>>y>>z;
path_add(x,y,z);
}
if(op==2)
{
cin>>y;
cout<<path_sum(x,y)<<"\n";
}
if(op==3)
{
cin>>z;
upd(dfn[x],dfn[x]+sz[x]-1,z);
}
if(op==4)
{
cout<<qry(dfn[x],dfn[x]+sz[x]-1)<<"\n";
}
}
return 0;
}