#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
#define int long long
#define maxn 100008
int tot,head[maxn],cnt,mod,n,m,r;
struct aaa{
int to,next;
}a[maxn];
struct bbb{
int sum,l,r,lazy;
}t[40*maxn];
int w[maxn];
struct ccc{
int size,deep,dfn,num,top,fa,son;
}tree[40*maxn];
void add(int x,int y)
{
a[tot].to=y;
a[tot].next=head[x];
head[x]=tot++;
}
void pushdown(int id)
{
int l=t[id].l;
int r=t[id].r;
int mid=(l+r)>>1;
if(t[id].lazy)
{
t[id<<1].sum+=t[id].lazy*(mid-l+1)%mod;
t[id<<1|1].sum+=t[id].lazy*(r-mid)%mod;
t[id<<1].lazy+=t[id].lazy%mod;
t[id<<1|1].lazy+=t[id].lazy%mod;
t[id].lazy=0;
}
}
void update(int id)
{
t[id].sum=(t[id<<1].sum+t[id<<1|1].sum)%mod;
}
void build(int id,int l,int r)
{
t[id].l=l;
t[id].r=r;
if(l==r)
{
t[id].sum=tree[w[l]].num%mod;
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
update(id);
}
void modify(int id,int x,int y,int z)
{
int l=t[id].l,r=t[id].r;
int mid=(l+r)>>1;
if(x<=l&&r<=y)
{
t[id].lazy+=z%mod;
t[id].sum+=z*(r-l+1)%mod;
return;
}
pushdown(id);
if(x<=mid)
modify(id<<1,x,y,z);
if(y>mid)
modify(id<<1|1,x,y,z);
update(id);
}
int query(int id,int x,int y)
{
int l=t[id].l,r=t[id].r;
int mid=(l+r)>>1;
if(x<=l&&r<=y)
return t[id].sum;
pushdown(id);
int ans=0;
if(x<=mid)
ans+=query(id<<1,x,y)%mod;
if(y>mid)
ans+=query(id<<1|1,x,y)%mod;
return ans%mod;
}
void dfs1(int u,int f)
{
tree[u].size=1;
tree[u].deep=tree[f].deep+1;
tree[u].fa=f;
int maxsize=-1;
for(int i=head[u];i!=-1;i=a[i].next)
{
int v=a[i].to;
if(v==f)
continue;
dfs1(v,u);
tree[u].size+=tree[v].size;
if(tree[v].size>maxsize)
{
maxsize=tree[v].size;
tree[u].son=v;
}
}
}
void dfs2(int u,int t)
{
tree[u].dfn=++cnt;
tree[u].top=t;
w[cnt]=u;
if(!tree[u].son)
return;
dfs2(tree[u].son,t);
for(int i=head[u];i!=-1;i=a[i].next)
{
int v=a[i].to;
if(v==tree[u].fa||v==tree[u].son)
continue;
dfs2(v,v);
}
}
void add_son(int x,int z)
{
modify(1,tree[x].dfn,tree[x].dfn+tree[x].size-1,z);
}
int query_son(int x)
{
return query(1,tree[x].dfn,tree[x].dfn+tree[x].size-1)%mod;
}
void mchain(int x,int y,int z)
{
z%=mod;
while(tree[x].top!=tree[y].top)
{
if(tree[tree[x].top].deep< tree[tree[y].top].deep)
swap(x,y);
modify(1,tree[tree[x].top].dfn,tree[x].dfn,z);
x=tree[tree[x].top].fa;
}
if(tree[x].deep>tree[y].deep)
swap(x,y);
modify(1,tree[x].dfn,tree[y].dfn,z);
}
int qchain(int x,int y)
{
int res=0;
while(tree[x].top!=tree[y].top)
{
if(tree[tree[x].top].deep<tree[tree[y].top].deep)
swap(x,y);
res+=query(1,tree[tree[x].top].dfn,tree[x].dfn)%mod;
x=tree[tree[x].top].fa;
}
if(tree[x].deep>tree[y].deep)
swap(x,y);
res+=query(1,tree[x].dfn,tree[y].dfn)%mod;
return res%mod;
}
signed main()
{
memset(head,-1,sizeof(head));
scanf("%lld%lld%lld%lld",&n,&m,&r,&mod);
for(int i=1;i<=n;i++)
scanf("%lld",&tree[i].num);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%lld%lld",&x,&y);
add(x,y);
add(y,x);
}
dfs1(r,r);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int d,x,y,z;
scanf("%lld",&d);
if(d==1)
scanf("%lld%lld%lld",&x,&y,&z),mchain(x,y,z);
if(d==2)
scanf("%lld%lld",&x,&y),printf("%lld\n",qchain(x,y)%mod);
if(d==3)
scanf("%lld%lld",&x,&y),add_son(x,y);
if(d==4)
scanf("%lld",&x),printf("%lld\n",query_son(x)%mod);
}
return 0;
}