#include<bits/stdc++.h>
#define int long long
#define INF 100000000000000
#define MAXN 100001
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n,m,r,p,cnt;
int val[MAXN];
struct node{
int x,id,top;
int dep,dad,maxson,size;
}a[MAXN];
struct tree{
int sum,tag;
}t[MAXN*4];
vector<int> e[MAXN];
void dfs1(int x,int dad,int d){
a[x].dep=d;
a[x].dad=dad;
int mx=-INF;
for(int i=0;i<e[x].size();i++)
if(e[x][i]!=dad){
int to=e[x][i];
dfs1(to,x,d+1);
a[x].size+=a[to].size;
if(a[to].size>mx){
a[x].maxson=to;
mx=a[to].size;
}
}
++a[x].size;
}
void dfs2(int x,int top){
a[x].id=++cnt;
val[cnt]=a[x].x;
a[x].top=top;
if(!a[x].maxson)
return ;
dfs2(a[x].maxson,top);
for(int i=0;i<e[x].size();i++)
if(e[x][i]!=a[x].dad&&e[x][i]!=a[x].maxson){
int to=e[x][i];
dfs2(to,to);
}
}
void build(int i,int l,int r){
if(l==r){
t[i].sum=val[l]%p;
t[i].tag=0;
return ;
}
int mid=(l+r)/2;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
t[i].tag=0;
t[i].sum=(t[i*2].sum+t[i*2+1].sum)%p;
}
void pushdown(int i,int l,int r){
t[i*2].tag+=t[i].tag;
t[i*2+1].tag+=t[i].tag;
int mid=(l+r)/2;
t[i*2].sum=(t[i*2].sum+(mid-l+1)*t[i].tag)%p;
t[i*2+1].sum=(t[i*2+1].sum+(r-mid)*t[i].tag)%p;
t[i].tag=0;
}
int query(int i,int l,int r,int L,int R){
if(L>R)
swap(L,R);
if(L<=l&&r<=R)
return t[i].sum;
if(l>R||r<L)
return 0;
int mid=(l+r)/2,sum=0;
if(t[i].tag)
pushdown(i,l,r);
if(mid>=L)
sum=(sum+query(i*2,l,mid,L,R))%p;
if(mid<R)
sum=(sum+query(i*2+1,mid+1,r,L,R))%p;
return sum;
}
void update(int i,int l,int r,int L,int R,int k){
if(L>R)
swap(L,R);
if(L<=l&&r<=R){
t[i].tag+=k;
t[i].sum=(t[i].sum+(r-l+1)*k)%p;
return ;
}
if(l>R||r<L)
return ;
int mid=(l+r)/2;
if(t[i].tag)
pushdown(i,l,r);
if(mid>=L)
update(i*2,l,mid,L,R,k);
if(mid<R)
update(i*2+1,mid+1,r,L,R,k);
}
int Qroute(int x,int y){
int ans=0;
while(a[x].top!=a[y].top){
if(a[a[x].top].dep<a[a[y].top].dep)
swap(x,y);
ans=(ans+query(1,1,n,a[a[x].top].id,a[x].id))%p;
x=a[a[x].top].dad;
}
if(a[x].dep<a[y].dep)
swap(x,y);
ans=(ans+query(1,1,n,a[x].id,a[y].id))%p;
return ans;
}
int Qtree(int root){
int ans=0;
ans=(ans+query(1,1,n,a[root].id,a[root].id+a[root].size-1))%p;
return ans;
}
int UProute(int x,int y,int k){
k=k%p;
while(a[x].top!=a[y].top){
if(a[a[x].top].dep<a[a[y].top].dep)
swap(x,y);
update(1,1,n,a[a[x].top].id,a[x].id,k);
x=a[a[x].top].dad;
}
if(a[x].dep<a[y].dep)
swap(x,y);
update(1,1,n,a[x].id,a[y].id,k);
}
int UPtree(int root,int k){
k=k%p;
update(1,1,n,a[root].id,a[root].id+a[root].size-1,k);
}
signed main(){
n=read(),m=read(),r=read(),p=read();
for(int i=1;i<=n;i++)
a[i].x=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int opt=read();
if(opt==1){
int x=read(),y=read(),z=read();
UProute(x,y,z);
}
else if(opt==2){
int x=read(),y=read();
cout<<Qroute(x,y)%p<<endl;
}
else if(opt==3){
int x=read(),k=read();
UPtree(x,k);
}
else{
int x=read();
cout<<Qtree(x)%p<<endl;
}
}
return 0;
}