#include<bits/stdc++.h>
#define ll long long
#define int long long
const int MAX=1e5+10;
using namespace std;
inline int read() {
int fh = 1, res = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
for(; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ '0');
res = res * fh;
return res;
}
inline void write(ll x) {
if(x<0){putchar('-');x=-x;}
if(x>9) write(x/10);
putchar(x%10+'0');
}
int p,n,ss,m;
vector<int> s[MAX];
int top[MAX],deep[MAX],son[MAX],siz[MAX],fa[MAX],bhs[MAX],bhwh[MAX],cnt;
struct xds{int l,r,w,f;}a[MAX<<2];
int ww[MAX],ans;
inline int lc(int k){return k<<1;}
inline int rc(int k){return k<<1|1;}
void dfs1(int f,int k)//树剖
{
deep[k]=deep[f]+1;
fa[k]=f;
siz[k]=1;
for(int i=0,sizz=s[k].size();i<sizz;i++)
{
if(s[k][i]==f) continue;
dfs1(k,s[k][i]);
siz[k]+=siz[s[k][i]];
if(siz[s[k][i]]>siz[son[k]])
son[k]=s[k][i];
}
return ;
}
void dfs2(int t,int k)//树剖
{
top[k]=t;
cnt++;
bhs[k]=cnt;
bhwh[cnt]=k;
if(!son[k]) return ;
dfs2(t,son[k]);
for(int i=0,sizz=s[k].size();i<sizz;i++)
{
if(s[k][i]==fa[k]) continue;
if(s[k][i]!=son[k]) dfs2(s[k][i],s[k][i]);
}
return ;
}
void down(int k)//线段树Lazy_tag下传
{
a[lc(k)].f+=a[k].f;a[rc(k)].f+=a[k].f;
a[lc(k)].w+=a[k].f*(a[lc(k)].r-a[lc(k)].l+1);
a[rc(k)].w+=a[k].f*(a[rc(k)].r-a[rc(k)].l+1);
if(a[lc(k)].f>=p) a[lc(k)].f%=p;if(a[rc(k)].f>=p) a[rc(k)].f%=p;
if(a[lc(k)].w>=p) a[lc(k)].w%=p;if(a[rc(k)].w>=p) a[rc(k)].w%=p;
a[k].f=0;
return ;
}
void build(int l,int r,int k)//线段树建树
{
a[k].l=l;a[k].r=r;
if(l==r)
{
a[k].w=ww[bhwh[k]];
if(a[k].w>=p) a[k].w%=p;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lc(k));
build(mid+1,r,rc(k));
a[k].w=a[lc(k)].w+a[rc(k)].w;
if(a[k].w>=p) a[k].w%=p;
return ;
}
void change(int l,int r,int z,int k)//线段树修改
{
if(a[k].l>=l&&a[k].r<=r)
{
a[k].w+=z;a[k].f+=z;
if(a[k].w>=p) a[k].w%=p;
if(a[k].f>=p) a[k].f%=p;
return ;
}
if(a[k].f) down(k);
int mid=(a[k].l+a[k].r)>>1;
if(l<=mid) change(l,r,z,lc(k));
if(mid+1<=r) change(l,r,z,rc(k));
a[k].w=a[lc(k)].w+a[rc(k)].w;
if(a[k].w>=p) a[k].w%=p;
return ;
}
void ask(int l,int r,int k)//线段树查询
{
if(a[k].l>=l&&a[k].r<=r)
{
ans+=a[k].w;
if(ans>=p) ans%=p;
return ;
}
if(a[k].f) down(k);
int mid=(a[k].l+a[k].r)>>1;
if(l<=mid) ask(l,r,lc(k));
if(mid+1<=r) ask(l,r,rc(k));
return ;
}
signed main()
{
n=read();m=read();ss=read();p=read();
for(int i=1;i<=n;i++) ww[i]=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
s[x].push_back(y);
s[y].push_back(x);
}
dfs1(0,ss);
dfs2(ss,ss);
build(1,n,1);
// for(int i=1;i<=n;i++) cout<<bhs[bhwh[i]]<<" ";
// cout<<endl;
while(m--)
{
int opt=read();
if(opt==1)
{
int x=read(),y=read(),z=read();
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
// change(bhs[top[x]],x,z,1);
change(bhs[top[x]],bhs[x],z,1);
x=fa[top[x]];
// y=fa[top[y]];
}
if(deep[x]>deep[y]) swap(x,y);
change(bhs[x],bhs[y],z,1);
}
if(opt==2)
{
ans=0;
int x=read(),y=read();
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ask(bhs[top[x]],bhs[x],1);
// ask(bhs[top[y]],y,1);
x=fa[top[x]];
// y=fa[top[y]];
}
if(deep[x]>deep[y]) swap(x,y);
ask(bhs[x],bhs[y],1);
write(ans);
putchar('\n');
}
if(opt==3)
{
int x=read(),z=read();
change(bhs[x],bhs[x]+siz[x]-1,z,1);
}
if(opt==4)
{
ans=0;
int x=read();
ask(bhs[x],bhs[x]+siz[x]-1,1);
write(ans);
putchar('\n');
}
}
return 0;
}
cpp```