#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
void read(int &a){
a=0;int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
a=a*10+ch-'0';
ch=getchar();
}
a=a*f;
}
int n,m,r,p,cnt,ans;
int a[100005];
struct node{
int x,id;
};
vector<node> v[100005];
int aa[100005];
int mxsonnumber[100005];
int size[100005],mxson[100005];
int depth[100005],fa[100005];
int in[100005],top[100005];
int tree[400005],lazy[400005];
void dfs1(int father,int x,int dep){
depth[x]=dep;
fa[x]=father;
size[x]=1;
for(int i=0;i<v[x].size();i++){
if(father==v[x][i].id)continue;
dfs1(x,v[x][i].id,dep+1);
size[x]+=size[v[x][i].id];
if(size[v[x][i].id]>mxsonnumber[x]){
mxsonnumber[x]=v[x][i].x;
mxson[x]=v[x][i].id;
}
}
return;
}
void dfs2(int x,int tp){
in[x]=++cnt;
aa[cnt]=a[x];
top[x]=tp;
if(!mxson[x])return;
dfs2(mxson[x],tp);
for(int i=0;i<v[x].size();i++){
if(v[x][i].id==fa[x]||v[x][i].id==mxson[x]){
continue;
}
dfs2(v[x][i].id,v[x][i].id);
}
}
void pushdown(int x,int l){
if(!lazy[x])return;
lazy[x*2]+=lazy[x];
lazy[x*2+1]+=lazy[x];
tree[x*2]+=lazy[x]*(l-l/2);
tree[x*2+1]+=lazy[x]*(l/2);
tree[x*2]%=p,tree[x*2+1]%=p;
lazy[x]=0;
}
void build(int x,int l,int r){
if(l==r){
tree[x]=aa[l]%p;
return;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x]=(tree[x*2]+tree[x*2+1])%p;
}
void query(int x,int l,int r,int ll,int rr){
if(l>rr||rr<l)return;
if(l>=ll&&r<=rr){
ans+=tree[x];
ans%=p;
return;
}
pushdown(x,r-l+1);
int mid=(l+r)/2;
query(x*2,l,mid,ll,rr);
query(x*2+1,mid+1,r,ll,rr);
}
void change(int x,int l,int r,int ll,int rr,int k){
if(l>rr||rr<l)return;
if(l>=ll&&r<=rr){
tree[x]+=k*(r-l+1);
lazy[x]+=k;
return;
}
pushdown(x,r-l+1);
int mid=(l+r)/2;
change(x*2,l,mid,ll,rr,k);
change(x*2+1,mid+1,r,ll,rr,k);
tree[x]=tree[x*2]+tree[x*2+1];
tree[x]%=p;
}
void change1(int x,int y,int k){
k%=p;
while(top[x]!=top[y]){
if(depth[top[x]]<depth[top[y]]){
swap(x,y);
}
change(1,1,n,in[top[x]],in[x],k);
x=fa[top[x]];
}
if(depth[x]>depth[y])swap(x,y);
change(1,1,n,in[x],in[y],k);
}
int query1(int x,int y){
int s=0;
while(top[x]!=top[y]){
if(depth[top[x]]<depth[top[y]]){
swap(x,y);
}
ans=0;
query(1,1,n,in[top[x]],in[x]);
s=(s+ans)%p;
x=fa[top[x]];
}
if(depth[x]>depth[y])swap(x,y);
ans=0;
query(1,1,n,in[x],in[y]);
return (ans+s)%p;
}
signed main(){
read(n),read(m),read(r),read(p);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1;i<n;i++){
int ll,rr;
read(ll),read(rr);
v[ll].push_back((node){a[rr],rr});
v[rr].push_back((node){a[ll],ll});
}
dfs1(0,r,1);
dfs2(r,r);
build(1,1,n);
while(m--){
int op;read(op);
if(op==1){
int l,r,x;
read(l),read(r),read(x);
change1(l,r,x);
}
else if(op==2){
int l,r;
read(l),read(r);
printf("%d\n",query1(l,r));
}
else if(op==3){
int x,y;
read(x),read(y);
change(1,1,n,in[x],in[x]+size[x]-1,y);
}
else{
int x;read(x);
ans=0;
query(1,1,n,in[x],in[x]+size[x]-1);
printf("%d\n",ans);
}
}
return 0;
}