#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define M 200005
using namespace std;
int n,m,r,p;
int x,y,z,ans;
int tot,cnt;
int w[N],head[N],dep[N],fa[N],size[N],son[N],idx[N],wt[N],top[N];
struct node{
int next,to;
}e[M];
struct Tree{
int l,r,lazy;
int w;
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
}tree[N<<2];
inline void pushup(int k){
tree[k].w=(tree[k<<1].w+tree[k<<1|1].w)%p;
}
inline void pushdown(int k){
tree[k<<1].lazy+=tree[k].lazy;
tree[k<<1|1].lazy+=tree[k].lazy;
tree[k<<1].w=(tree[k<<1].w+tree[k].lazy*(tree[k<<1].r-tree[k<<1].l+1)%p)%p;
tree[k<<1|1].w=(tree[k<<1|1].w+tree[k].lazy*(tree[k<<1|1].r-tree[k<<1|1].l+1)%p)%p;
tree[k].lazy=0;
}
void build(int k,int l,int r){
tree[k].l=l; tree[k].r=r;
if(tree[k].l==tree[k].r){
tree[k].w=wt[l];
if(tree[k].w>p) tree[k].w%=p;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
build(lson);
build(rson);
pushup(k);
}
void change(int k){
if(tree[k].l>=x && tree[k].r<=y){
tree[k].w+=(tree[k].r-tree[k].l+1)*z;
tree[k].lazy+=z;
return;
}
if(tree[k].lazy) pushdown(k);
int mid=(tree[k].r+tree[k].l)>>1;
if(x<=mid) change(k<<1);
if(y>mid) change(k<<1|1);
pushup(k);
}
void query(int k){
if(tree[k].l>=x && tree[k].r<=y){
ans=(ans+tree[k].w)%p;
return;
}
if(tree[k].lazy) pushdown(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(x<=mid) query(k<<1);
if(y>mid) query(k<<1|1);
}
inline void add(int u,int v){
e[++tot].to=v;
e[tot].next=head[u];
head[u]=tot;
}
void dfs1(int u,int f,int deep){
dep[u]=deep;
fa[u]=f;
size[u]=1;
int maxson=-1;
for(int i=head[u],v;i;i=e[i].next){
v=e[i].to;
if(v==f) continue;
dfs1(v,u,deep+1);
size[u]+=size[v];
if(size[v]>maxson){
son[u]=v;
maxson=size[v];
}
}
}
void dfs2(int u,int topf){
idx[u]=++cnt;
wt[cnt]=w[u];
top[u]=topf;
if(!son[u]) return;
dfs2(son[u],topf);
for(int i=head[u],v;i;i=e[i].next){
v=e[i].to;
if(v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
}
inline int qrange(int u,int v){
int res=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans=0;
x=top[idx[u]]; y=idx[u];
query(1);
res=(res+ans)%p;
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans=0;
x=idx[u]; y=idx[v];
query(1);
res=(res+ans)%p;
return res;
}
inline void updrange(int u,int v){
z%=p;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
x=top[idx[u]]; y=idx[u];
change(1);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
x=idx[u]; y=idx[v];
change(1);
}
int main(){
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
int opt;
while(m--){
ans=0;
scanf("%d",&opt);
if(opt==1){
scanf("%d%d%d",&x,&y,&z);
updrange(x,y);
}
else if(opt==2){
scanf("%d%d",&x,&y);
printf("%d\n",qrange(x,y));
}
else if(opt==3){
scanf("%d%d",&x,&z);
y=idx[x]+size[x]-1; x=idx[x];
change(1);
}
else if(opt==4){
scanf("%d",&x);
y=idx[x]+size[x]-1; x=idx[x];
query(1);
printf("%d\n",ans);
}
}
return 0;
}