#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+10;
struct edge{
int v,nxt;
}e[2*maxn];
struct Node{
int sum,lazy;
}tree[2*maxn];
int n,m,r,P;
int a[maxn],cnt,p[maxn];
int f[maxn],d[maxn],sz[maxn];
int son[maxn],rk[maxn];
int top[maxn],id[maxn];
void init(){
memset(p,-1,sizeof(p));
cnt=0;
}
void add(int u,int v){
e[++cnt].v=v;
e[cnt].nxt=p[u];
p[u]=cnt;
}
int mod(int x,int y){
return (x+y)%P;
}
void dfs1(int u,int fa,int h){
f[u]=fa;
d[u]=h;
sz[u]=1;
for(int i=p[u];i!=-1;i=e[i].nxt){
int v=e[i].v;
if(v==fa) continue;
dfs1(v,u,h+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t;
id[u]=++cnt;
rk[cnt]=u;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=p[u];i!=-1;i=e[i].nxt){
int v=e[i].v;
if(v!=son[u]&&v!=f[u]) dfs2(v,v);
}
}
void pushup(int x,int l,int r){
tree[x].sum=((tree[x*2].sum+tree[x*2+1].sum)%P+tree[x].lazy*(r-l+1)%P)%P;
}
void pushdown(int o,int l,int r){
int mid=(l+r)>>1;
tree[o*2].sum=mod(tree[o*2].sum,tree[o].lazy*(mid-l+1)%P);
tree[o*2].lazy=mod(tree[o*2].lazy,tree[o].lazy);
tree[o*2+1].sum=mod(tree[o*2+1].sum,tree[o].lazy*(r-mid)%P);
tree[o*2+1].lazy=mod(tree[o*2+1].lazy,tree[o].lazy);
tree[o].lazy=0;
}
void build(int now,int l,int r){
tree[now].lazy=0;
if(l==r){
tree[now].sum=1;
return;
}
int mid=(l+r)>>1;
build(now*2,l,mid);
build(now*2+1,mid+1,r);
pushup(now,l,r);
}
void update(int now,int l,int r,int ql,int qr,int c){
if(ql<=l&&r<=qr){
tree[now].sum=mod(tree[now].sum,c*(r-l+1));
tree[now].lazy=mod(tree[now].lazy,c);
return;
}
if(tree[now].lazy) pushdown(now,l,r);
int mid=(l+r)>>1;
if(ql<=mid) update(now*2,l,mid,ql,qr,c);
if(qr>mid) update(now*2+1,mid+1,r,ql,qr,c);
pushup(now,l,r);
}
int query(int now,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return tree[now].sum;
if(tree[now].lazy) pushdown(now,l,r);
int val=tree[now].lazy*(min(qr,r)-max(ql,l))%P;
int mid=(l+r)>>1;
if(ql<=mid) val=(val+query(now*2,l,mid,ql,qr))%P;
if(mid<qr) val=(val+query(now*2+1,mid+1,r,ql,qr))%P;
return val;
}
int getsum(int x,int y){
int ans=0;
int fx=top[x],fy=top[y];
while(fx!=fy){
if(d[fx]>=d[fy]){
ans=mod(ans,query(1,1,n,id[fx],id[x]));
x=f[fx];
fx=top[x];
}else{
ans=mod(ans,query(1,1,n,id[fy],id[y]));
y=f[fy];
fy=top[y];
}
}
if(id[x]<=id[y]) ans=mod(ans,query(1,1,n,x,y));
else ans=mod(ans,query(1,1,n,y,x));
return ans;
}
void change(int x,int y,int c){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(d[fx]>=d[fy]){
update(1,1,n,id[fx],id[x],c);
x=f[fx];
fx=top[x];
}else{
update(1,1,n,id[fy],id[y],c);
y=f[fy];
fy=top[y];
}
}
if(id[x]<=id[y]) update(1,1,n,id[x],id[y],c);
else update(1,1,n,id[y],id[x],c);
}
signed main(){
scanf("%lld %lld %lld %lld",&n,&m,&r,&P);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
init();
for(int i=1;i<n;i++){
int x,y;
scanf("%lld %lld",&x,&y);
add(x,y);
add(y,x);
}
cnt=0;
dfs1(r,0,1);
cnt=0;
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y,z;
scanf("%lld",&op);
if(op==1){
scanf("%lld %lld %lld",&x,&y,&z);
change(x,y,z);
}else if(op==2){
scanf("%lld %lld",&x,&y);
printf("%lld\n",getsum(x,y));
}else if(op==3){
scanf("%lld %lld",&x,&z);
update(1,1,n,id[x],id[x]+sz[x]-1,z);
}else{
scanf("%lld",&x);
printf("%lld\n",query(1,1,n,id[x],id[x]+sz[x]-1));
}
}
return 0;
}