#include<bits/stdc++.h>
#define ls(x) x<<1
#define rs(x) x<<1|1
#define I inline
#define LL long long
#define RI register int
#define maxn 100010
using namespace std;
I int read()
{
RI res=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
return res*f;
}
struct Tree{
int l,r;
LL sum;
}tree[maxn*4];
LL lazy[maxn*4];
int n,m,root;LL mod;
int val[maxn],a[maxn];
int head[maxn],tot;
struct node{
int to,next;
}edge[maxn*2];
I void add(int x,int y)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
}
int deep[maxn],son[maxn],top[maxn],id[maxn],size[maxn],f[maxn];
int cnt;
I void build(int l,int r,int id)
{
tree[id].l=l;tree[id].r=r;
if(l==r){tree[id].sum=a[l];return ;}
int mid=(l+r)>>1;
build(l,mid,ls(id));
build(mid+1,r,rs(id));
tree[id].sum=(tree[ls(id)].sum+tree[rs(id)].sum)%mod;
return;
}
I void pushdown(int x)
{
if(!lazy[x])return;
tree[ls(x)].sum=(tree[ls(x)].sum+(tree[ls(x)].r-tree[ls(x)].l+1)*lazy[x])%mod;
tree[rs(x)].sum=(tree[rs(x)].sum+(tree[rs(x)].r-tree[rs(x)].l+1)*lazy[x])%mod;
lazy[ls(x)]=(lazy[ls(x)]+lazy[x])%mod;
lazy[rs(x)]=(lazy[rs(x)]+lazy[x])%mod;
lazy[x]=0;
return ;
}
I void change(int l,int r,LL k,int id)
{
if(tree[id].l>=l&&tree[id].r<=r)
{
lazy[id]=(lazy[id]+k)%mod;
tree[id].sum=(tree[id].sum+(tree[id].r-tree[id].l+1)*k)%mod;
return;
}
pushdown(id);
if(tree[ls(id)].r>=l)change(l,r,k,ls(id));
if(tree[rs(id)].l<=r)change(l,r,k,rs(id));
tree[id].sum=(tree[ls(id)].sum+tree[rs(id)].sum)%mod;
return;
}
I LL getsum(int l,int r,int id)
{
if(tree[id].l>=l&&tree[id].r<=r)return tree[id].sum;
pushdown(id);
LL ans=0;
if(tree[ls(id)].r>=l)ans+=getsum(l,r,ls(id)),ans%=mod;
if(tree[rs(id)].l<=r)ans+=getsum(l,r,rs(id)),ans%=mod;
return ans;
}
I void dfs1(int x,int fa)
{
f[x]=fa;
size[x]=1;
deep[x]=deep[fa]+1;
int maxson=-1;
for(RI i=head[x];i;i=edge[i].next)
{
int to=edge[i].to;
if(to==fa)continue;
dfs1(to,x);
size[x]+=size[to];
if(size[to]>maxson)maxson=size[to],son[x]=to;
}
}
I void dfs2(int x,int tp)
{
id[x]=++cnt;
a[cnt]=val[x];
top[x]=tp;
if(!son[x])return;
dfs2(son[x],tp);
for(RI i=head[x];i;i=edge[i].next)
{
int to=edge[i].to;
if(to==f[x]||to==son[x])continue;
dfs2(to,to);
}
}
I LL ask(int x,int y)
{
LL ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=getsum(id[ top[x] ],id[x],1);
ans%=mod;
x=f[ top[x] ];
}
if(deep[x]>deep[y]) swap(x,y);
ans+=getsum(id[x],id[y],1);
ans%=mod;
return ans;
}
int main()
{
n=read();m=read();root=read();mod=read();
for(RI i=1;i<=n;i++)val[i]=read();
for(RI i=1;i<n;i++)
{
int u,v;u=read();v=read();
add(u,v);add(v,u);
}
dfs1(root,0);
dfs2(root,root);
build(1,n,1);
while(m--)
{
int op;
op=read();
if(op==1)
{
int x,y;LL z;x=read();y=read();cin>>z;
change(x,y,z,1);
}
else
{
if(op==2)
{
int x,y;x=read();y=read();
printf("%lld\n",ask(x,y));
}
else
{
if(op==3)
{
int x;LL z;
x=read();cin>>z;
change(id[x],id[x]+size[x]-1,z,1);
}
else
{
int x;
x=read();
printf("%lld\n",getsum(id[x],id[x]+size[x]-1,1));
}
}
}
}
return 0;
}