不知道为什么会RE
#include<bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
typedef long long ll;
using namespace std;
inline ll read(){ll x=0,f=1;char c=getchar();while(c<48||c>57){if(c==45)f=0;c=getchar();}while(c>47&&c<58)x=(x<<3)+(x<<1)+(c^48),c=getchar();return f?x:-x;}
const ll maxn=1e5+5;
ll n,m,root,mod,top[maxn],dep[maxn],fa[maxn],siz[maxn],son[maxn],head[maxn],tot,dfn[maxn],id[maxn],cnt,a[maxn];
struct edge{ll to,nxt;}e[maxn<<1];
inline void add(ll u,ll v){e[++tot]=(edge){v,head[u]},head[u]=tot;}
//以下为线段树模板
struct linetree{ll v,lazy;}t[maxn<<2];
inline void buildtree(ll x,ll l,ll r){
if(l==r){
t[x].v=a[id[l]]%mod;
return;
}
buildtree(ls,l,mid);
buildtree(rs,mid+1,r);
t[x].v=(t[ls].v+t[rs].v+mod)%mod;
}
inline void pushdown(ll x,ll l,ll r){
if(t[x].lazy){
t[ls].lazy+=t[x].lazy,t[rs].lazy+=t[x].lazy;
t[ls].v+=t[x].lazy*(mid-l+1),t[ls].v%=mod;
t[rs].v+=t[x].lazy*(r-mid),t[rs].v%=mod;
t[x].lazy=0;
}
}
inline void treeupdate(ll x,ll l,ll r,ll s,ll e,ll val){
if(s<=l&&r<=e){
t[x].lazy+=val,t[x].lazy%=mod;
t[x].v+=val*(r-l+1),t[x].v%=mod;
return;
}
pushdown(x,l,r);
if(mid>=s)treeupdate(ls,l,mid,s,e,val);
if(mid<e)treeupdate(rs,mid+1,r,s,e,val);
t[x].v=(t[ls].v+t[rs].v+mod)%mod;
}
inline ll treeask(ll x,ll l,ll r,ll s,ll e){
if(s<=l&&r<=e)return t[x].v;
pushdown(x,l,r);
ll ans=0;
if(mid>=s)ans+=treeask(ls,l,mid,s,e);
if(mid<e)ans+=treeask(rs,mid+1,r,s,e);
return ans%mod;
}
//以上为线段树模板
//以下为重链剖分模板
inline void dfs1(ll u,ll pre){
fa[u]=pre,siz[u]=1,dep[u]=dep[pre]+1;
for(ll i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(v==pre)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
inline void dfs2(ll u,ll tf){
top[u]=tf,dfn[u]=++cnt,id[cnt]=u;
if(son[u])dfs2(son[u],tf);
for(ll i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
// inline ll lca(ll u,ll v){
// while(top[u]!=top[v]){
// if(dep[fa[top[u]]]<dep[fa[top[v]]])swap(u,v);
// u=fa[top[u]];
// }
// if(dep[u]>dep[v])swap(u,v);
// return u;
// }
inline ll query(ll u,ll v){
ll ans=0;
while(top[u]!=top[v]){
if(dep[fa[top[u]]]<dep[fa[top[v]]])swap(u,v);
ans+=treeask(1,1,n,dfn[top[u]],dfn[u]),ans%=mod;
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
ans+=treeask(1,1,n,dfn[u],dfn[v]),ans%=mod;
return ans;
}
inline void modify(ll u,ll v,ll w){
while(top[u]!=top[v]){
if(dep[fa[top[u]]]<dep[fa[top[v]]])swap(u,v);
treeupdate(1,1,n,dfn[top[u]],dfn[u],w);
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
treeupdate(1,1,n,dfn[u],dfn[v],w);
}
//以上为重链剖分模板
signed main(){
n=read(),m=read(),root=read(),mod=read();
for(ll i=1;i<=n;++i)a[i]=read();
for(ll i=1;i<n;++i){
ll u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(root,0),dfs2(root,root),buildtree(1,1,n);
while(m--){
ll opt=read();
if(opt==1){
ll x=read(),y=read(),z=read();modify(x,y,z);
}
else if(opt==2){
ll x=read(),y=read();printf("%lld\n",query(x,y));
}
else if(opt==3){
ll x=read(),z=read();treeupdate(1,1,n,dfn[x],dfn[x]+siz[x]-1,z%mod);
}
else{
ll x=read();printf("%lld\n",treeask(1,1,n,dfn[x],dfn[x]+siz[x]-1));
}
}
return 0;
}