#include<iostream>
#include<cstring>
#define mid (l+r)/2
#define left now<<1
#define right now<<1|1
using namespace std;
inline int read(){
int x=0,zf=1;char c=getchar();
while (c<'0'||c>'9'){
if (c=='-')zf=-1;
c=getchar();
}
while (c>='0'&&c<='9'){
x=x*10+c-'0';c=getchar();
}
return x*zf;
}
struct ab{
int next,to;
}e[100005];
struct bc{
int sum,lazy;
}tree[4*100005];
int N,M,R,P,num[100005],top[100005],dep[100005],sz[100005],hson[100005],fa[100005],dfsn[100005],maf[100005],dfsn2[100005],cont,cnt,head[100005];
void add(int x,int y){
e[++cnt].next=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs1(int nod,int dp){
dep[nod]=dp;sz[nod]=1;
for (int i=head[nod];i;i=e[i].next){
if (fa[nod]==e[i].to)continue;
fa[e[i].to]=nod;
dfs1(e[i].to,dp+1);
sz[nod]+=sz[e[i].to];
if (sz[hson[nod]]<sz[e[i].to]){
hson[nod]=e[i].to;
}
}
}
void dfs2(int nod){
dfsn[nod]=maf[nod]=++cont;
dfsn2[cont]=nod;
if (hson[nod]!=0){
top[hson[nod]]=top[nod];
dfs2(hson[nod]);
maf[nod]=max(maf[nod],maf[hson[nod]]);
}
for (int i=head[nod];i;i=e[i].next){
if (maf[e[i].to]!=0)continue;
dfs2(e[i].to);top[e[i].to]=e[i].to;
if (maf[e[i].to]>maf[nod]){
maf[nod]=maf[e[i].to];
}
}
}
void build(int now,int l,int r){
if (l==r){
tree[now].sum=num[dfsn2[l]];
return ;
}
build(left,l,mid);
build(right,mid+1,r);
tree[now].sum=tree[left].sum+tree[right].sum;tree[now].sum%=P;
return ;
}
void pushdown(int now,int l,int r){
if (tree[now].lazy==0)return ;
tree[left].lazy+=tree[now].lazy;
tree[left].sum+=tree[now].lazy*(mid-l+1);
tree[right].lazy+=tree[now].lazy;
tree[right].sum+=tree[now].lazy*(r-mid);
tree[now].lazy=0;
}
void update(int now,int l,int r,int x,int y,int z){
if (x<=l&&r<=y){
tree[now].lazy+=z;tree[now].lazy%=P;
tree[now].sum+=z*(r-l+1);tree[now].sum%=P;
return ;
}
pushdown(now,l,r);
if (mid>=x)update(left,l,mid,x,y,z);
if (mid<y)update(right,mid+1,r,x,y,z);
tree[now].sum=tree[left].sum+tree[right].sum;tree[now].sum%=P;
}
int query(int now,int l,int r,int x,int y){
if (x<=l&&r<=y){
return tree[now].sum;
}
pushdown(now,l,r);
int sum=0;
if (mid>=x)sum+=query(left,l,mid,x,y);
if (mid<y)sum+=query(right,mid+1,r,x,y);
sum%=P;
return sum;
}
int update_path(int x,int y,int z){
while (top[x]!=top[y]){
if (dep[top[x]]>dep[top[y]]){
update(1,1,N,dfsn[top[x]],dfsn[x],z);
x=fa[top[x]];
}
else{
update(1,1,N,dfsn[top[y]],dfsn[y],z);
y=fa[top[y]];
}
}
if (dep[x]>dep[y]){
update(1,1,N,dfsn[y],dfsn[x],z);
}
else{
update(1,1,N,dfsn[x],dfsn[y],z);
}
}
void query_path(int x,int y){
int sum=0;
while (top[x]!=top[y]){
if (dep[top[x]]>dep[top[y]]){
sum+=query(1,1,N,dfsn[top[x]],dfsn[x]);sum%=P;
x=fa[top[x]];
}
else{
sum+=query(1,1,N,dfsn[top[y]],dfsn[y]);sum%=P;
y=fa[top[y]];
}
}
if (dep[x]>dep[y]){
sum+=query(1,1,N,dfsn[y],dfsn[x]);sum%=P;
}
else{
sum+=query(1,1,N,dfsn[x],dfsn[y]);sum%=P;
}
cout<<sum%P<<endl;
}
void update_subtree(int x,int z){
update(1,1,N,dfsn[x],maf[x],z);
}
void query_subtree(int x){
cout<<query(1,1,N,dfsn[x],maf[x])%P<<endl;
}
signed main(){
N=read();M=read();R=read();P=read();
for (int i=1;i<=N;i++){
num[i]=read();
}
for (int i=1;i<N;i++){
int x=read(),y=read();
add(x,y);add(y,x);
}
top[R]=R;fa[R]=R;
dfs1(R,1);dfs2(R);
build(1,1,N);
for (int i=1;i<=M;i++){
int pan=read();
switch (pan){
case 1:{
int x=read(),y=read(),z=read();update_path(x,y,z);break;
}
case 2:{
int x=read(),y=read();query_path(x,y);break;
}
case 3:{
int x=read(),z=read();update_subtree(x,z);break;
}
case 4:{
int x=read();query_subtree(x);break;
}
}
}
return 0;
}