#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int totr;
int i1,i2;
long long i3;
int n,m,r,tot;
long long a[N],p;
int dfsx[N],dfsk[N];
int sizes[N],dep[N],maxson[N],fa[N],fot[N],endn[N];
int head[N];
struct node{
int u,v,nex;
}t[N];
struct trees{
int l,r;
long long num,add;
}tr[4*N];
void add(int u,int v){
t[++totr]=(node){u,v,head[u]};
head[u]=totr;
}
void build(int l,int r,int id){
tr[id].l=l,tr[id].r=r;
if(l==r){
tr[id].num=a[dfsk[l]];
tr[id].num%=p;
return;
}
int mid=(l+r)>>1;
build(l,mid,id*2);
build(mid+1,r,id*2+1);
tr[id].num=(tr[2*id].num+tr[2*id+1].num)%p;
// printf("%d %d %d\n",l,r,tr[id].num);
}
void Size_dfs(int u){
int maxn=0;
sizes[u]=1,maxson[u]=0;
for(int i=head[u];i;i=t[i].nex){
int v=t[i].v;
if(v==fa[u]) continue;
fa[v]=u;
dep[v]=dep[u]+1;
Size_dfs(v);
sizes[u]+=sizes[v];
if(sizes[v]>maxn){
maxn=sizes[v];
maxson[u]=v;
}
}
}
void Subdivision(int u,int beg){
++tot;
dfsx[tot]=u;
dfsk[u]=tot;
if(u==beg) fot[u]=u;
if(maxson[u]!=0){
fot[maxson[u]]=beg;
Subdivision(maxson[u],beg);
for(int i=head[u];i;i=t[i].nex){
int v=t[i].v;
if(v==maxson[u]||v==fa[u]) continue;
Subdivision(v,v);
}
}
endn[u]=tot;
}
void pushdown(int id){
if(tr[id].add!=0){
tr[2*id].add+=tr[id].add;tr[2*id].add%=p;
tr[2*id+1].add+=tr[id].add;tr[2*id+1].add%=p;
tr[2*id].num+=(tr[2*id].r-tr[2*id].l+1)*tr[id].add;tr[2*id].num%=p;
tr[2*id+1].num+=(tr[2*id+1].r-tr[2*id+1].l+1)*tr[id].add;tr[2*id+1].num%=p;
tr[id].add=0;
}
}
void add_sub(int x,int y,long long num,int id){
int l=tr[id].l,r=tr[id].r;
if(x<=l&&y>=r){
tr[id].num+=(r-l+1)*num;tr[id].num%=p;
tr[id].add+=num;tr[id].add%=p;
return;
}
pushdown(id);
int mid=(l+r)>>1;
if(x<=mid) add_sub(x,y,num,id*2);
if(y>mid) add_sub(x,y,num,id*2+1);
tr[id].num=(tr[2*id].num+tr[2*id+1].num)%p;
}
void add_xy(int x,int y,long long num){
if(fot[x]!=fot[y]){
if(dep[y]>dep[x]) swap(x,y);
add_sub(dfsk[fot[x]],dfsk[x],num,1);
x=fa[fot[x]];
}
if(dep[y]>dep[x]) swap(x,y);
add_sub(dfsk[x],dfsk[y],num,1);
}
long long find_sub(int x,int y,int id){
int l=tr[id].l,r=tr[id].r,ans=0;
int mid=(l+r)>>1;
if(x<=l&&y>=r) return tr[id].num%p;
/*
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].num);
}
printf("\n");
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].add);
}
printf("\n");
*/ pushdown(id);
if(x<=mid) ans+=find_sub(x,y,id*2);ans%=p;
if(y>mid) ans+=find_sub(x,y,id*2+1);ans%=p;
return ans;
}
long long find_xy(int x,int y){
long long ans=0;
while(fot[x]!=fot[y]){
if(dep[y]>dep[x]) swap(x,y);
ans+=find_sub(dfsk[fot[x]],dfsk[x],1);
x=fa[fot[x]];
}
if(dep[y]>dep[x]) swap(x,y);
ans+=find_sub(dfsk[x],dfsk[y],1);
ans%=p;
return ans;
}
void add_subtree(int root,long long num){
add_sub(dfsk[root],endn[root],num,1);
}
long long find_subtree(int root){
return find_sub(dfsk[root],endn[root],1)%p;
}
int main(){
scanf("%d%d%d%lld",&n,&m,&r,&p);
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<n;i++){
scanf("%d%d",&i1,&i2);
add(i1,i2);add(i2,i1);
}
fa[r]=r;
Size_dfs(r);Subdivision(r,r);build(1,n,1);
/*
for(int i=1;i<=n;i++){
printf("%d %d %d %d %d %d\n",sizes[i],dep[i],fot[i],maxson[i],dfsk[i],endn[i]);
}
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].num);
}
printf("\n");
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].add);
}
printf("\n");
*/
for(int i=1;i<=m;i++){
scanf("%d",&i1);
if(i1==1){
scanf("%d%d%lld",&i1,&i2,&i3);
add_xy(i1,i2,i3);
}
else if(i1==2){
scanf("%d%d",&i1,&i2);
printf("%lld\n",find_xy(i1,i2));
}
else if(i1==3){
scanf("%d%lld",&i1,&i3);
//printf("%d %d\n",dfsk[i1],endn[i1]);
add_subtree(i1,i3);
}
else{
scanf("%d",&i1);
printf("%lld\n",find_subtree(i1));
}
/*
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].num);
}
printf("\n");
for(int i=1;i<=2*n-1;i++){
printf("%d ",tr[i].add);
}
printf("\n");
*/
}
return 0;
}