#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
int read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=1e5+10;
int head[N<<2],cnt;
int siz[N<<2],dis[N],pos[N<<2],tot,top[N<<2],fa[N<<2],her[N<<2],dfn[N<<2],laz[N<<2],tr[N<<2];
int n,m,r,p,a[N];
//---------------------------------------------------------定义变量
struct edge
{
int v,nxt;
}e[N<<2];
void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
//----------------------------------------------------------链式前向星建图
void add1(int k,int l,int r,int v){
laz[k]+=v;tr[k]+=(r-l+1)*v;
return;
}
void pushup(int k,int l,int r){
tr[k]=tr[ls]+tr[rs]+(r-l+1)*laz[k];
}
void build(int k,int l,int r){
if(l==r){
tr[k]=a[dfn[l]];
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k,l,r);
return;
}
void change(int k,int l,int r,int x,int y,ll v){
//assert(x<=y);
if(x<=l&&r<=y){
add1(k,l,r,v);
return;
}
if(x<=mid)change(ls,l,mid,x,y,v);
if(y>mid)change(rs,mid+1,r,x,y,v);
pushup(k,l,r);
return;
}
int ask(int k,int l,int r,int x,int y){
//assert(x<=y);
if(x<=l&&r<=y)return tr[k];
ll res=(min(y,r)-max(x,l)+1)*laz[k];
if(x<=mid)res+=ask(ls,l,mid,x,y)%p;
if(y>mid)res+=ask(rs,mid+1,r,x,y)%p;
return res%p;
}
//---------------------------------------------线段树
void dfs1(int x,int f){
fa[x]=f,dis[x]=dis[f]+1,siz[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==f)continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>=siz[her[x]])her[x]=v;
}
}
void dfs2(int x,int tp){
top[x]=tp,dfn[++tot]=x,pos[x]=tot;
if(her[x])dfs2(her[x],tp);
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa[x]||v==her[x])continue;
dfs2(v,v);
}
}
void upd(int x,int y,ll v) {
//printf("upd: x=%lld y=%lld",x,y);
while(top[x]!=top[y]) {
if(dis[top[x]]<dis[top[y]]) swap(x,y);
change(1,1,n,pos[top[x]],pos[x],v);
//printf(" jump: x=%lld (%lld %lld)\n",x,pos[top[x]],pos[x]);
x=fa[top[x]];
}
if(dis[x]<dis[y]) swap(x,y);
//printf(" jump: %lld %lld\n",pos[y],pos[x]);
change(1,1,n,pos[y],pos[x],v);
}
int query(int x,int y) {
int ans=0;
while(top[x]!=top[y]) {
if(dis[top[x]]<dis[top[y]]) swap(x,y);
ans+=ask(1,1,n,pos[top[x]],pos[x])%p;
x=fa[top[x]];
}
if(dis[x]<dis[y]) swap(x,y);
ans+=ask(1,1,n,pos[y],pos[x])%p;
return ans%p;
}
//-------------------------------------------------以上为树链剖分
signed main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read(),m=read(),r=read(),p=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n-1;i++){
int x,y;
x=read(),y=read();
add(x,y);
add(y,x);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int opt;
//cout<<"i="<<i<<endl;
opt=read();
if(opt==1){
int x,y,z;
x=read(),y=read(),z=read();
upd(x,y,z);
}
else if(opt==2){
int x,y;
x=read(),y=read();
printf("%lld\n",query(x,y)%p);
}
else if(opt==3){
int x,y;
x=read(),y=read();
for(int i=pos[x];i<=pos[x]+siz[x];i++){
a[i]+=y%p;
//printf("a=%d\n",a[i]);
}
}
else {
int res=0;
int x;
x=read();
for(int i=pos[x];i<=pos[x]+siz[x];i++){
res+=a[i]%p;
}
printf("%lld\n",res%p);
}
}
return 0;
}
1~7wa 8~10tle 11AC