wa7
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e6;
int n,m,root,p;
struct edge{
int to,nxt;
}e[N];
int head[N],cnt=0,ans,cont=0,siz[N],a[N],tp[N],rec[N],id[N],vis[N],son[N],fa[N],dep[N];
void add(int u,int v){
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs1(int u,int ffa){
siz[u]=1;
fa[u]=ffa;
dep[u]=dep[ffa]+1;
for(int i=head[u];i;i=e[i].nxt){
int y=e[i].to;
if(y==ffa)continue;
dfs1(y,u);
siz[u]+=siz[y];
if(siz[y]>siz[son[u]]){
son[u]=y;
}
}
}
void dfs2(int u,int t){
tp[u]=t;
id[u]=++cont;
rec[cont]=u;
if(!son[u])return;
dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[u]||y==son[u])continue;
dfs2(y,y);
}
}
struct tree{
int l,r,sum,tag;
}t[N*4];
void updata(int x){
t[x].sum=(t[x*2].sum+t[x*2+1].sum)%p;
}
void build(int x,int l,int r){
t[x].l=l;t[x].r=r;
if(t[x].l==t[x].r){
t[x].sum=a[rec[l]]%p;
return;
}
int mid=(l+r)/2;
build(x*2,l,mid),
build(x*2+1,mid+1,r);
updata(x);
}
void down(int x){
t[x*2].tag+=t[x].tag%p;
t[x*2+1].tag+=t[x].tag%p;
t[x*2].sum+=(t[x].tag*(t[x*2].r-t[x*2].l+1))%p;t[x*2].sum%=p;
t[x*2+1].sum+=(t[x].tag*(t[x*2+1].r-t[x*2+1].l+1))%p;t[x*2+1].sum%=p;
t[x].tag=0;
}
void list_modify(int x,int l,int r,int k){
if(t[x].l>r||t[x].r<l)return;
else if(t[x].l>=l&&t[x].r<=r){
t[x].sum=(t[x].sum+(t[x].r-t[x].l+1)*k)%p;
t[x].tag=(t[x].tag+k)%p;
return;
}
down(x);
list_modify(x*2,l,r,k);
list_modify(x*2+1,l,r,k);
updata(x);
}
int list_query(int x,int l,int r){
if(t[x].l>r||t[x].r<l)return 0;
else if(t[x].l>=l&&t[x].r<=r)return t[x].sum%p;
down(x);
return (list_query(x*2,l,r)%p+list_query(x*2+1,l,r)%p)%p;
}
void tree_updata(int u,int v,int k){
while(tp[u]!=tp[v]){
if(dep[tp[u]]<dep[tp[v]])swap(u,v);
list_modify(1,id[tp[u]],id[u],k);
u=fa[tp[u]];
}
if(dep[u]>dep[v]){
swap(u,v);
}
list_modify(1,id[u],id[v],k);
}
int tree_query(int u,int v){
ans=0;
while(tp[u]!=tp[v]){
if(dep[tp[u]]<dep[tp[v]])swap(u,v);
ans=(ans+list_query(1,id[tp[u]],id[u]))%p;
u=fa[tp[u]];
}
if(dep[u]>dep[v]){
swap(u,v);
}
ans=(ans+list_query(1,id[u],id[v]))%p;
return ans%p;
}
void sontree_modify(int x,int z){
list_modify(1,id[x],id[x]+siz[son[x]],z);
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==son[x]||y==fa[x])continue;
sontree_modify(y,z);
}
}
int sontree_query(int x){
ans=0;
if(!son[x])return list_query(1,id[x],id[x])%p;
ans=(ans+list_query(1,id[x],id[x]+siz[son[x]]))%p;
ans%=p;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==son[x]||y==fa[x])continue;
ans=(ans+sontree_query(y))%p;
}
return ans%p;
}
signed main(){
//freopen("t1.in","r",stdin);
//freopen("t1.out","w",stdout);
cin>>n>>m>>root>>p;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);add(v,u);
}
dfs1(root,0);dfs2(root,root);
build(1,1,n);
for(int i=1;i<=m;i++){
int op,l,r,x;
cin>>op;
if(op==1){
cin>>l>>r>>x;
tree_updata(l,r,x);
}
else if(op==2){
cin>>l>>r;
cout<<tree_query(l,r)%p<<endl;
}
else if(op==3){
cin>>l>>x;
sontree_modify(l,x);
}
else{
cin>>l;
cout<<sontree_query(l)%p<<endl;
}
}
//fclose(stdin);
//fclose(stdout);
return 0;
}