#include<bits/stdc++.h>
using namespace std;
const int MAXX=200000+100;
long long N,M,R,P;
long long zhi[MAXX];
long long deep[MAXX];
long long size[MAXX];
long long son[MAXX];
long long F[MAXX];
long long SUM[MAXX];
long long Z_top[MAXX];
long long id_dian[MAXX];
long long id_dui[MAXX];
struct EVA{
long long next,to;
}tree[MAXX];
struct cjc{
long long l,r,id,num,lazy;
}x_TREE[MAXX*2];
long long head[MAXX],cnt=0;
void build(long long u,long long v){
tree[++cnt].to=v;
tree[cnt].next=head[u];
head[u]=cnt;
}
void dfs_1(long long id,long long fa,long long depth){
size[id]=1;
deep[id]=depth;
F[id]=fa;
for(long long i=head[id];i;i=tree[i].next){
long long v=tree[i].to;
if(v==fa)continue;
dfs_1(v,id,depth+1);
size[id]+=size[v];
if(size[v]>=size[son[id]]){
son[id]=v;
}
}
}
long long xu=0;
void dfs_2(long long id,long long z_t){
Z_top[id]=z_t;
id_dian[id]=++xu;
id_dui[xu]=id;
if(!son[id])return ;
dfs_2(son[id],z_t);
for(long long i=head[id];i;i=tree[i].next){
long long v=tree[i].to;
if(v!=F[id] && v!=son[id]){
dfs_2(v,v);
}
}
}
void Build(long long id,long long l,long long r){
x_TREE[id].l=l;
x_TREE[id].r=r;
if(l==r){
x_TREE[id].num=SUM[id_dui[l]];
return ;
}
long long mid=(l+r)/2;
Build(id*2,l,mid);
Build(id*2+1,mid+1,r);
x_TREE[id].num+=(x_TREE[id*2].num+x_TREE[id*2+1].num)%P;
}
void pushdown(long long id){
x_TREE[id*2].lazy+=x_TREE[id].lazy%P;
x_TREE[id*2+1].lazy+=x_TREE[id].lazy%P;
x_TREE[id*2].num+=(x_TREE[id*2].r-x_TREE[id*2].l+1)*x_TREE[id].lazy%P;
x_TREE[id*2+1].num+=(x_TREE[id*2+1].r-x_TREE[id*2+1].l+1)*x_TREE[id].lazy%P;
x_TREE[id].lazy=0;
}
void J(long long id,long long L,long long R,long long jia){
if(x_TREE[id].l>=L && x_TREE[id].r<=R){
x_TREE[id].lazy+=jia%P;
x_TREE[id].num+=jia*(x_TREE[id].r-x_TREE[id].l+1)%P;
return ;
}
pushdown(id);
long long mid=(x_TREE[id].l+x_TREE[id].r)/2;
if(mid+1<=L)J(id*2+1,L,R,jia);
else if(mid>=R)J(id*2,L,R,jia);
else {
J(id*2,L,R,jia);
J(id*2+1,L,R,jia);
}
x_TREE[id].num=x_TREE[id*2].num+x_TREE[id*2+1].num;
}
long long quihe(long long id,long long L,long long R){
if(x_TREE[id].l>=L && x_TREE[id].r<=R){
return x_TREE[id].num%P;
}
pushdown(id);
long long mid=(x_TREE[id].l+x_TREE[id].r)/2;
if(mid<L)return quihe(id*2+1,L,R);
else if(mid>=R){
return quihe(id*2,L,R);
}
else {
long long ans=0;
long long mid=(x_TREE[id].l+x_TREE[id].r)/2;
ans+=quihe(id*2,L,mid)%P;
ans+=quihe(id*2,mid+1,R)%P;
ans%=P;
return ans;
}
}
void J_(long long x,long long y,long long val){
val%=P;
long long fx=Z_top[x];
long long fy=Z_top[y];
while(fx!=fy){
if(deep[Z_top[x]]>=deep[Z_top[y]]){
J(1,id_dian[fx],id_dian[x],val);
x=F[fx];
fx=Z_top[x];
}
else{
J(1,id_dian[fy],id_dian[y],val);
y=F[fy];
fy=Z_top[y];
}
}
if(id_dian[x]<id_dian[y]){
J(1,id_dian[x],id_dian[y],val);
}
else {
J(1,id_dian[y],id_dian[x],val);
}
}
long long qiu(long long x,long long y){
long long fx=Z_top[x];
long long fy=Z_top[y];
long long ans=0;
while(fx!=fy){
if(deep[Z_top[x]]>=deep[Z_top[y]]){
ans+=quihe(1,id_dian[fx],id_dian[x])%P;
x=F[fx];
fx=Z_top[x];
}
else{
ans+=quihe(1,id_dian[fy],id_dian[y])%P;
y=F[fy];
fy=Z_top[y];
}
}
ans%=P;
if(id_dian[x]<id_dian[y]){
ans+=quihe(1,id_dian[x],id_dian[y])%P;
}
else {
ans+=quihe(1,id_dian[y],id_dian[x])%P;
}
return ans;
}
int main(){
cin>>N>>M>>R>>P;
for(long long i=1;i<=N;i++)cin>>SUM[i];
for(long long i=1;i<=N-1;i++){
long long a,b;
cin>>a>>b;
build(a,b);
build(b,a);
}
dfs_1(R,0,1);
dfs_2(R,R);
Build(1,1,N);
long long op,x,y,z;
for(long long i=1;i<=M;i++){
cin>>op;
if(op==1){
cin>>x>>y>>z;
J_(x,y,z%P);
}
else if(op==2){
cin>>x>>y;
cout<<qiu(x,y)<<endl;
}
else if(op==3){
cin>>x>>z;
J(1,id_dian[x],id_dian[x]+size[x]-1,z%P);
}
else{
cin>>x;
cout<<quihe(1,id_dian[x],id_dian[x]+size[x]-1)%P<<endl;
}
}
return 0;
}