#include<bits/stdc++.h>
#define LL long long
#define pii pair<LL,int>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
struct TMD{
int to,next;
}edge[maxn<<1];
int head[maxn],cnt,knt,n,m,r;
int f[maxn],deep[maxn],sz[maxn],sn[maxn];
int tree[maxn],pre[maxn],top[maxn],val[maxn];
LL sum[maxn<<2],p,lazy[maxn<<2];
void add(int from,int to){
edge[++cnt]={to,head[from]};
head[from]=cnt;
}
void dfs1(int now,int fa){
deep[now]=deep[fa]+1;
f[now]=fa;
sz[now]=1;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
dfs1(to,now);
sz[now]+=sz[to];
if(!sn[now]||sz[sn[now]]<sz[to]) sn[now]=to;
}
}
void dfs2(int now,int fa,int tp){
tree[now]==++knt;pre[knt]=now;
top[now]=tp;
if(!sn[now]) return ;
dfs2(sn[now],now,tp);
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to;
if(to==fa||to==sn[now]) continue;
dfs2(to,now,to);
}
}
void build(int l,int r,int rt){
lazy[rt]=0;
if(l==r) {
sum[rt]=val[pre[l]]%p;return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
}
void pushdown(int l,int r,int rt){
int mid=(l+r)>>1;
if(lazy[rt]){
lazy[rt<<1]=(lazy[rt<<1]+lazy[rt])%p;
lazy[rt<<1|1]=(lazy[rt<<1|1]+lazy[rt])%p;
sum[rt<<1]=(sum[rt<<1]+1ll*(mid-l+1)*lazy[rt]%p)%p;
sum[rt<<1|1]=(sum[rt<<1|1]+1ll*(r-mid)*lazy[rt]%p)%p;
lazy[rt]=0;
}
}
void modify(int L,int R,int l,int r,int rt,int k){
if(L<=l&&R>=r){
lazy[rt]+=k;
sum[rt]=(sum[rt]+1ll*(r-l+1)*k)%p;return ;
}
pushdown(l,r,rt);
int mid=(l+r)>>1;
if(L<=mid) modify(L,R,l,mid,rt<<1,k);
if(R>mid) modify(L,R,mid+1,r,rt<<1|1,k);
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
}
LL dfs_sum1(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return sum[rt];
pushdown(l,r,rt);
int mid=(l+r)>>1;
LL ans=0;
if(L<=mid) ans=(ans+dfs_sum1(L,R,l,mid,rt<<1))%p;
if(R>mid) ans=(ans+dfs_sum1(L,R,mid+1,r,rt<<1|1))%p;
return ans;
}
LL get_sum(int x,int y){
int f1=top[x],f2=top[y];
LL ans=0;
while(f1!=f2){
if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
ans=(ans+dfs_sum1(tree[f1],tree[x],1,n,1))%p;
x=f[f1],f1=top[x];
}
if(deep[x]<deep[y]) swap(x,y);
ans=(ans+dfs_sum1(tree[y],tree[x],1,n,1))%p;
return ans;
}
void dfs_sum2(int x,int y,int k){
int f1=top[x],f2=top[y];
while(f1!=f2){
if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
modify(tree[f1],tree[x],1,n,1,k);
x=f[f1],f1=top[x];
}
if(deep[x]<deep[y]) swap(x,y);
modify(tree[y],tree[x],1,n,1,k);
}
int main(){
mem(head,-1);
int u,v,w,opt;
scanf("%d%d%d%lld",&n,&m,&r,&p);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs1(r,0);
dfs2(r,0,r);
build(1,n,1);
for(int i=1;i<=m;i++) {
scanf("%d", &opt);
if(opt==1){
scanf("%d%d%d",&u,&v,&w);
dfs_sum2(u,v,w);
}
else if(opt==2){
scanf("%d%d",&u,&v);
printf("%lld\n",get_sum(u,v));
}
else if(opt==3){
scanf("%d%d",&u,&v);
modify(tree[u],tree[u]+sz[u]-1,1,n,1,v);
}
else {
scanf("%d",&u);
printf("%lld\n",dfs_sum1(tree[u],tree[u]+sz[u]-1,1,n,1));
}
}
return 0;
}