#include<bits/stdc++.h>
using namespace std;
const int M=1e5+10;
int n,m,r,p,w[M];
struct edgenode{int to,next;}edge[M<<1];
int head[M],cnte;
void add(int u,int v){
edge[++cnte].to=v;
edge[cnte].next=head[u];
head[u]=cnte;
}
//树剖
int depth[M],fa[M],son[M],size[M];
void dfs1(int u,int f){
fa[u]=f;
size[u]=1;
depth[u]=depth[f]+1;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==f) continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
int top[M],id[M],rev[M],cnt;
void dfs2(int u){
id[u]=++cnt,rev[cnt]=u;
if(u==son[fa[u]]) top[u]=top[fa[u]];
else top[u]=u;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v!=fa[u]) dfs2(v);
}
}
//线段树
struct segmenttree{int l,r,val,lazy;}tree[M<<2];
void pushup(int k){tree[k].val=(tree[k<<1].val+tree[k<<1|1].val)%p;}
void pushdown(int k){
if(tree[k].lazy==0) return;
tree[k<<1].val=(tree[k<<1].val+tree[k].lazy*(tree[k<<1].r-tree[k<<1].l+1))%p;
tree[k<<1|1].val=(tree[k<<1|1].val+tree[k].lazy*(tree[k<<1|1].r-tree[k<<1|1].l+1))%p;
tree[k<<1].lazy=(tree[k<<1].lazy+tree[k].lazy)%p;
tree[k<<1|1].lazy=(tree[k<<1|1].lazy+tree[k].lazy)%p;
tree[k].lazy=0;
}
void build(int k,int l,int r){
tree[k].l=l,tree[k].r=r;
if(l==r){
tree[k].val=w[id[l]];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void update(int l,int r,int k,int val){
if(tree[k].l>=l&&tree[k].r<=r){
tree[k].val=(tree[k].val+val*(tree[k].r-tree[k].l+1))%p;
tree[k].lazy=(tree[k].lazy+val)%p;
return;
}
pushdown(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(mid>=l) update(l,r,k<<1,val);
if(mid<r) update(l,r,k<<1|1,val);
pushup(k);
}
int query(int l,int r,int k){
if(tree[k].l>=l&&tree[k].r<=r) return tree[k].val;
pushdown(k);
int mid=(tree[k].l+tree[k].r)>>1,sum=0;
if(mid>=l) sum+=query(l,r,k<<1);
if(mid<r) sum+=query(l,r,k<<1|1);
return sum%p;
}
void chainupdate(int u,int v,int val){
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(u,v);
update(id[top[u]],id[u],1,val);
u=fa[top[u]];
}
if(id[u]>id[v]) swap(u,v);
update(id[u],id[v],1,val);
}
int chainquery(int u,int v){
int sum=0;
while(top[u]!=top[v]){
if(depth[top[u]]<depth[top[v]]) swap(u,v);
sum=(sum+query(id[top[u]],id[u],1))%p;
u=fa[top[u]];
}
if(id[u]>id[v]) swap(u,v);
sum=(sum+query(id[u],id[v],1))%p;
return sum;
}
void print(){
for(int i=1;i<=n;i++) printf("%d ",query(i,i,1));
putchar('\n');
}
int main(){
for(int i=0;i<M;i++) head[i]=-1;
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1,x,y;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs1(r,0),dfs2(r);
build(1,1,n);
for(int i=1,op,x,y,z;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d",&x,&y,&z);
chainupdate(x,y,z%p);
}
if(op==2){
scanf("%d%d",&x,&y);
printf("%d\n",chainquery(x,y));
}
if(op==3){
scanf("%d%d",&x,&z);
update(id[x],id[x]+size[x]-1,1,z%p);
}
if(op==4){
scanf("%d",&x);
printf("%d\n",query(id[x],id[x]+size[x]-1,1));
}
//print();
}
return 0;
}