RT
#include <bits/stdc++.h>
using namespace std;
int depth[200005],size[200005],son[200005],fa[200005],top[200005],rk[200005],tot,di[200005],din[200005];
vector<int> edge[200005];
struct tree{
int to,laz;
}tr[800005];
int p,ansx,n,m,R;
void pushup(int u){
tr[u].to=tr[u*2].to+tr[u*2+1].to;
}
void build(int l,int r,int u){
if (l==r){
tr[u].to=din[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,u*2);
build(mid+1,r,u*2+1);
pushup(u);
return ;
}
void pushdown(int l,int r,int u){
if (l==r||!tr[u].laz) return ;
tr[u*2].laz+=tr[u].laz;
tr[u*2].laz%=p;
tr[u*2+1].laz+=tr[u].laz;
tr[u*2+1].laz%=p;
int mid=(l+r)/2;
tr[u*2].to+=tr[u].laz*(mid-l+1);
tr[u*2].to%=p;
tr[u*2+1].to+=tr[u].laz*(r-mid);
tr[u*2+1].to%=p;
tr[u].laz=0;
return ;
}
void update(int l,int r,int L,int R,long long la,int u){
if (l>=L&&r<=R){
tr[u].to+=la*(r-l+1);
tr[u].to%=p;
tr[u].laz+=la;
tr[u].laz%=p;
return ;
}
pushdown(l,r,u);
int mid=(l+r)/2;
if (mid>=L) update(l,mid,L,R,la,u*2);
if (mid<R) update(mid+1,r,L,R,la,u*2+1);
pushup(u);
return ;
}
long long getsum(int l,int r,int L,int R,int u){
if (l>=L&&r<=R) return tr[u].to;
pushdown(l,r,u);
int ans=0;
int mid=(l+r)/2;
if (mid>=L) ans+=getsum(l,mid,L,R,u*2);
if (mid<R) ans+=getsum(mid+1,r,L,R,u*2+1);
ans%=p;
return ans;
}
void dfs1(int dep,int now,int fat){
depth[now]=dep;
fa[now]=fat;
size[now]=1;
int len=edge[now].size();
int maxx=-1e9;
for (register int i=0;i<len;i++){
int qwq=edge[now][i];
if (qwq==fat) continue ;
dfs1(dep+1,qwq,now);
size[now]+=size[qwq];
if (size[qwq]>maxx) maxx=size[qwq],son[now]=qwq;
}
return ;
}
void dfs2(int now,int tf){
rk[now]=++tot;
top[now]=tf;
din[tot]=di[now];
if (!son[now]) return ;
int len=edge[now].size();
dfs2(son[now],tf);
for (register int i=0;i<len;i++){
int qwq=edge[now][i];
if (qwq==fa[now]||qwq==son[now]) continue ;
dfs2(qwq,qwq);
}
return ;
}
int czmg(int x,int y){
int ans=0;
while(top[x]!=top[y]){
if (depth[x]<depth[y]) swap(x,y);
ans+=getsum(1,n,rk[top[x]],rk[x],1);
ans%=p;
x=fa[top[x]];
}
if (depth[x]>depth[y]) swap(x,y);
ans+=getsum(1,n,rk[x],rk[y],1);
ans%=p;
return ans;
}
void czmg2(int x,int y,int k){
while(top[x]!=top[y]){
if (depth[x]<depth[y]) swap(x,y);
update(1,n,rk[top[x]],rk[x],k,1);
x=fa[top[x]];
}
if (depth[x]>depth[y]) swap(x,y);
update(1,n,rk[x],rk[y],k,1);
return ;
}
int ask1(int x){
int ans=getsum(1,n,rk[x],rk[x]+size[x]-1,1);
return ans;
}
void cha(int x,int k){
update(1,n,rk[x],rk[x]+size[x]-1,k,1);
return ;
}
int main(){
cin >> n >> m >> R >> p;
for (register int i=1;i<=n;i++){
cin >> di[i];
}
for (register int i=1;i<=n-1;i++){
int x,y;
cin >> x >> y;
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs1(1,R,0);
dfs2(R,R);
build(1,n,1);
for (register int i=1;i<=m;i++){
int op;
cin >> op;
if (op==1){
int x,y,z;
cin >> x >> y >> z;
czmg2(x,y,z);
}
if (op==2){
int x,y;
cin >> x >> y;
cout << czmg(x,y) << endl;
}
if (op==3){
int x,y,z;
cin >> x >> z;
cha(x,z);
}
if (op==4){
int x;
cin >> x;
cout << ask1(x) << endl;
}
}
}