#include<bits/stdc++.h>
using namespace std;
int n,m,root,key,a[100005];
int head[100005],to[200005],nextt[200005],tot;
int fa[100005],sizee[100005],zson[100005],deep[100005];
int lian[100005],place[100005],top[100005],cnt;
struct s{
long long sum,lazy;int lc,rc;
}tree[400005];
void dfs1(int mark,int last)
{
fa[mark]=last;sizee[mark]=1;
for(register int j=head[mark];j;j=nextt[j])
{
int y=to[j];if(y==last)continue;
deep[y]=deep[mark]+1;
dfs1(y,mark);
sizee[mark]+=sizee[y];
if(sizee[y]>sizee[zson[mark]])zson[mark]=y;
}
}
void dfs2(int mark,int tp)
{
lian[++cnt]=mark;place[mark]=cnt;top[mark]=tp;
if(zson[mark])dfs2(zson[mark],tp);
for(register int j=head[mark];j;j=nextt[j])
{
int y=to[j];if(y==fa[mark])continue;if(y==zson[mark])continue;
dfs2(y,y);
}
}
void pushdown(int mark)
{
if(!tree[mark].lazy)return;
long long num=tree[mark].lazy;
tree[mark<<1].sum+=num*(tree[mark<<1].rc-tree[mark<<1].rc+1)%key;
tree[mark<<1|1].sum+=num*(tree[mark<<1|1].rc-tree[mark<<1|1].lc+1)%key;
tree[mark<<1].sum%=key;tree[mark<<1|1].sum%=key;
tree[mark<<1].lazy+=num;tree[mark<<1|1].lazy+=num;
tree[mark].lazy=0;
}
void build(int mark,int l,int r)
{
tree[mark].lc=l;tree[mark].rc=r;
if(l==r){tree[mark].sum=a[lian[l]];return;}
int mid;mid=(l+r)>>1;
build(mark<<1,l,mid);build(mark<<1|1,mid+1,r);
tree[mark].sum=tree[mark<<1].sum+tree[mark<<1|1].sum;
tree[mark].sum%=key;
}
void add(int mark,int l,int r,long long num)
{
if(tree[mark].lc>=l&&tree[mark].rc<=r)
{
tree[mark].lazy+=num;tree[mark].lazy%=key;
tree[mark].sum+=num*(tree[mark].rc-tree[mark].lc+1);
tree[mark].sum%=key;return;
}
pushdown(mark);
int mid;mid=(tree[mark].lc+tree[mark].rc)>>1;
if(l<=mid)add(mark<<1,l,r,num);
if(r>=mid+1)add(mark<<1|1,l,r,num);
tree[mark].sum=tree[mark<<1].sum+tree[mark<<1|1].sum;
tree[mark].sum%=key;
}
void change(int x,int y,long long num)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
add(1,place[top[x]],place[x],num);
x=fa[top[x]];
}
if(deep[x]<deep[y])swap(x,y);
add(1,place[y],place[x],num);
}
long long findsum(int mark,int l,int r)
{
if(tree[mark].lc>=l&&tree[mark].rc<=r)return tree[mark].sum;
pushdown(mark);
int mid;mid=(tree[mark].lc+tree[mark].rc)>>1;
long long ans=0;
if(l<=mid)ans+=findsum(mark<<1,l,r);ans%=key;
if(mid+1<=r)ans+=findsum(mark<<1|1,l,r);
return ans%key;
}
long long qsum(int x,int y)
{
long long ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
ans+=findsum(1,place[top[x]],place[x]);
ans%=key;
x=fa[top[x]];
}
if(deep[x]<deep[y])swap(x,y);
ans+=findsum(1,place[y],place[x]);
return ans%key;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&root,&key);
for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
for(register int i=1;i<n;i++)
{
int g1,g2;scanf("%d%d",&g1,&g2);
to[++tot]=g2;nextt[tot]=head[g1];head[g1]=tot;
to[++tot]=g1;nextt[tot]=head[g2];head[g2]=tot;
}
dfs1(root,root);dfs2(root,root);build(1,1,n);
for(register int i=1;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x,y;long long z;scanf("%d%d%lld",&x,&y,&z);
change(x,y,z);
}
if(op==2)
{
int x,y;scanf("%d%d",&x,&y);
printf("%lld\n",qsum(x,y));
}
if(op==3)
{
int x;long long y;scanf("%d%lld",&x,&y);
add(1,place[x],place[x]+sizee[x]-1,y);
}
if(op==4)
{
int x;scanf("%d",&x);
printf("%lld\n",findsum(1,place[x],place[x]+sizee[x]-1));
}
}
}