#include<bits/stdc++.h>
#define ll long long
#define reg register
#define db double
#define il inline
using namespace std;
void read(int &x){x=0;int f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;}
void read(ll &x){x=0;int f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;}
const int N=1e5+5;
int n,m,rt,mod;
int deep[N],fa[N],dfn[N],dfnr[N],idfn[N],son[N],top[N],sz[N],tim;
vector<int>g[N];
void dfs(int x){
deep[x]=deep[fa[x]]+1;
sz[x]=1;
for(int i:g[x]){
if(i==fa[x])continue;
fa[i]=x;dfs(i);
sz[x]+=sz[i];
if(sz[i]>sz[son[x]])son[x]=i;
}
}
void dfs2(int x,int tp){
top[x]=tp;
dfn[x]=++tim;idfn[tim]=x;
if(!son[x]){
dfnr[x]=tim;return;
}
dfs2(son[x],tp);
for(int i:g[x]){
if(i==son[x])continue;
if(i==fa[x])continue;
dfs2(i,i);
}
dfnr[x]=tim;
}
ll a[N],tree[N<<2],tag[N<<2];
void push_down(int x,int l,int r){
int mid=(l+r)/2;
tree[x<<1]+=tag[x]*(mid-l+1)%mod;tree[x<<1|1]+=tag[x]*(r-mid)%mod;
tree[x<<1]%=mod;tree[x<<1|1]%=mod;
tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
tag[x]=0;
}
void push_up(int x){
tree[x]=tree[x<<1]+tree[x<<1|1];tree[x]%=mod;
}
void build(int x,int l,int r){
if(l==r){
tree[x]=a[idfn[l]]%mod;return;
}
int mid=(l+r)/2;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
push_up(x);
}
void update(int x,int l,int r,int ql,int qr,int w){
if(ql<=l&&qr>=r){
tree[x]+=(r-l+1)*w%mod;tree[x]%=mod;
tag[x]+=w;return;
}
int mid=(l+r)/2;
push_down(x,l,r);
if(ql<=mid)update(x<<1,l,mid,ql,qr,w);
if(qr>mid)update(x<<1|1,mid+1,r,ql,qr,w);
push_up(x);
}
ll query(int x,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r)return tree[x];
ll re=0;int mid=(l+r)/2;
push_down(x,l,r);
if(ql<=mid)re=query(x<<1,l,mid,ql,qr);
if(qr>mid)re=(re+query(x<<1|1,mid+1,r,ql,qr))%mod;
return re%mod;
}
void update2(int x,int y,ll z){
while(top[x]!=top[y]){
if(deep[x]>deep[y]){
update(1,1,n,dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}else{
update(1,1,n,dfn[top[y]],dfn[y],z);
y=fa[top[y]];
}
}
update(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),z);
}
ll query2(int x,int y){
ll re=0;
while(top[x]!=top[y]){
if(deep[x]>deep[y]){
re+=query(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}else{
re+=query(1,1,n,dfn[top[y]],dfn[y]);
y=fa[top[y]];
}
re%=mod;
}
re+=query(1,1,n,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]));
return re%mod;
}
int main(){
read(n);read(m);read(rt);read(mod);
for(int i=1;i<=n;i++)read(a[i]);
for(int u,v,i=1;i<n;i++){
read(u);read(v);
g[u].push_back(v);g[v].push_back(u);
}
dfs(rt);dfs2(rt,rt);
build(1,1,n);
while(m--){
int op,x,y,z;
read(op);
if(op==1){
read(x);read(y);read(z);
update2(x,y,z);
}else if(op==2){
read(x);read(z);
printf("%lld\n",query2(x,z));
}else if(op==3){
read(x);read(z);
update(1,1,n,dfn[x],dfnr[x],z);
}else{
read(x);
printf("%lld\n",query(1,1,n,dfn[x],dfnr[x]));
}
}
return 0;
}