#include <bits/stdc++.h>
#define int long long
using namespace std;
struct str{
int l,r,v,add;
}tr[400005];
int a[100005];
int b[100005];
int d[100005];
int son[100005];
int father[100005];
int sz[100005];
int in[100005];
int top[100005];
int tot;
vector<int>g[100005];
void pushup(int p) {
tr[p].v=tr[p<<1].v+tr[p<<1|1].v;
}
void pushdown(int p) {
int mid=(tr[p].l+tr[p].r)>>1;
if(tr[p].add!=0) {
tr[p<<1].v+=tr[p].add*(mid-tr[p].l+1);
tr[p<<1|1].v+=tr[p].add*(tr[p].r-mid);
tr[p<<1].add+=tr[p].add;
tr[p<<1|1].add+=tr[p].add;
tr[p].add=0;
}
}
void build(int p,int x,int y) {
tr[p].l=x;
tr[p].r=y;
if(x==y) {
tr[p].v=b[x];
return;
}
int mid=(x+y)>>1;
build(p<<1,x,mid);
build(p<<1|1,mid+1,y);
pushup(p);
}
void update(int p,int x,int y,int v) {
if(x<=tr[p].l&&tr[p].r<=y) {
tr[p].v+=v*(tr[p].r-tr[p].l+1);
tr[p].add+=v;
return;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)>>1;
if(x<=mid){
update(p<<1,x,y,v);
}
if(y>mid){
update(p<<1|1,x,y,v);
}
pushup(p);
}
int query(int p,int x,int y) {
if(x<=tr[p].l&&tr[p].r<=y){
return tr[p].v;
}
pushdown(p);
int mid=(tr[p].l+tr[p].r)>>1;
int ans=0;
if (x<=mid){
ans+=query(p<<1,x,y);
}
if(y>mid){
ans+=query(p<<1|1,x,y);
}
return ans;
}
void dfs1(int u,int f){
father[u]=f;
d[u]=d[f]+1;
sz[u]=1;
for(int i:g[u]){
if(i==f){
continue;
}
dfs1(i,u);
sz[u]+=sz[i];
if(sz[i]>sz[son[u]]){
son[u]=i;
}
}
}
void dfs2(int u,int t){
tot++;
in[u]=tot;
top[u]=t;
if(!son[u]){
return;
}
dfs2(son[u],t);
for(int i:g[u]){
if(i==son[u]||i==father[u]){
continue;
}
dfs2(i,i);
}
}
void decupdate(int x,int y,int k){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]){
swap(x,y);
}
update(1,in[top[x]],in[x],k);
x=father[top[x]];
}
if(d[x]<d[y]){
swap(x,y);
}
update(1,in[y],in[x],k);
}
int decquery(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]){
swap(x,y);
}
ans+=query(1,in[top[x]],in[x]);
x=father[top[x]];
}
if(d[x]<d[y]){
swap(x,y);
}
ans+=query(1,in[y],in[x]);
return ans;
}
void decupdate_subtree(int x,int k){
update(1,in[x],in[x]+sz[x]-1,k);
}
int decquery_subtree(int x){
return query(1,in[x],in[x]+sz[x]-1);
}
signed main(){
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
int n,m,r,p;
cin>>n>>m>>r>>p;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(r,0);
dfs2(r,0);
for(int i=1;i<=n;i++){
b[in[i]]=a[i];
}
build(1,1,n);
for(int i=1;i<=m;i++){
int f;
cin>>f;
if(f==1){
int x,y,k;
cin>>x>>y>>k;
decupdate(x,y,k);
}
if(f==2){
int x,y;
cin>>x>>y;
cout<<decquery(x,y)%p<<"\n";
}
if(f==3){
int x,k;
cin>>x>>k;
decupdate_subtree(x,k);
}
if(f==4){
int x;
cin>>x;
cout<<decquery_subtree(x)%p<<"\n";
}
}
}