#include <bits/stdc++.h> using namespace std; #define ll long long #define re register #define pb push_back #define fi first #define se second const int N=1e6+10; const int mod7=1e9+7; void read(int &a) { a=0;int d=1;char ch; while(ch=getchar(),ch>'9'||ch<'0') if(ch=='-') d=-1; a=ch^48; while(ch=getchar(),ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48); a*=d; } vector <int> v[N]; int siz[N],dep[N],f[N],son[N],top[N],id[N],rk[N],cnt,val[N]; int n,m,root,mod; struct note{int l,r,sum,lazy;}tree[N<<1]; void dfs1(int x) { siz[x]=1,dep[x]=dep[f[x]]+1; for(auto i:v[x]) { if(i!=f[x]) { f[i]=x;dfs1(i),siz[x]+=siz[i]; if(siz[son[x]]<siz[i]) son[x]=i; } } } void dfs2(int x,int tp) { top[x]=tp,id[x]=++cnt,rk[cnt]=x; if(son[x]) dfs2(son[x],tp); for(auto i:v[x]) if(i!=f[x]&&i!=son[x]) dfs2(i,i); } void work(int now,int k) { (tree[now].sum+=1ll*(tree[now].r-tree[now].l+1)*k%mod)%=mod; tree[now].lazy+=k; } void pushdown(int now) { work(now<<1,tree[now].lazy); work(now<<1|1,tree[now].lazy); tree[now].lazy=0; return; } void build(int l,int r,int now) { tree[now].l=l,tree[now].r=r; if(l==r) {tree[now].sum=val[rk[l]]%mod;return;} int m=l+r>>1; build(l,m,now<<1),build(m+1,r,now<<1|1); tree[now].sum=(tree[now<<1].sum+tree[now<<1|1].sum)%mod; } void modify(int l,int r,int now,int w) { if(tree[now].l>=l&&tree[now].r<=r){work(now,w);return;} if(tree[now].lazy) pushdown(now); int m=tree[now].l+tree[now].r>>1; if(m>=l) modify(l,r,now<<1,w); if(m<r) modify(l,r,now<<1|1,w); tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum; } int query(int now,int l,int r) { if(tree[now].l>=l&&tree[now].r<=r) return tree[now].sum; if(tree[now].lazy) pushdown(now); int m=tree[now].l+tree[now].r>>1,res=0; if(l<=m) res=(res+query(now<<1,l,r))%mod; if(m<r) res=(res+query(now<<1|1,l,r))%mod; return res; } void update(int x,int y,int z) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); modify(id[top[x]],id[x],1,z); x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); modify(id[x],id[y],1,z); } int query1(int x,int y) { int res=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); res=(res+query(1,id[top[x]],id[x]))%mod; x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); res=(res+query(1,id[x],id[y]))%mod; return res; } int main() { read(n),read(m),read(root),read(mod); for(re int i=1;i<=n;i++) read(val[i]); for(re int i=1,x,y;i<n;i++) read(x),read(y),v[x].pb(y),v[y].pb(x); dfs1(root);dfs2(root,root); build(1,n,1); for(re int op,x,y,k,i=1;i<=m;i++) { read(op); if(op==1) read(x),read(y),read(k),update(x,y,k); else if(op==2) read(x),read(y),printf("%d ",query1(x,y)); else if(op==3) read(x),read(y),modify(id[x],id[x]+siz[x]-1,1,y); else if(op==4) read(x),printf("%d ",query(1,id[x],id[x]+siz[x]-1)); } return 0; }