#include<bits/stdc++.h>
using namespace std;
int n,m,r,p;
int w[100005];
int dep[100005],fa[100005],son[100005],siz[100005];
int id[100005],wt[100005],top[100005],cnt;
int head[500005],num_edge;
struct Edge
{
int nxt,to;
}edge[500005];
void add_edge (int from,int to)
{
edge[++num_edge].nxt=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
struct node
{
int val,addmark;
}segtree[400005];
void build(int root,int start,int end)
{
segtree[root].addmark=0;
if (start==end) segtree[root].val=wt[start]%p;
else
{
int mid=(start+end)/2;
build(root*2,start,mid);
build(root*2+1,mid+1,end);
segtree[root].val=segtree[root*2].val+segtree[root*2+1].val;
segtree[root].val%=p;
}
}
void pushdown(int root,int l1,int r1,int l2,int r2)
{
if (segtree[root].addmark!=0)
{
segtree[root*2].addmark+=segtree[root].addmark;
segtree[root*2+1].addmark+=segtree[root].addmark;
segtree[root*2].val+=segtree[root].addmark*(r1-l1+1);
segtree[root*2].val%=p;
segtree[root*2+1].val+=segtree[root].addmark*(r2-l2+1);
segtree[root*2+1].val%=p;
segtree[root].addmark=0;
}
}
int query(int root,int nstart,int nend,int qstart,int qend)
{
if (qstart>nend||qend<nstart) return 0;
if (qstart<=nstart&&qend>=nend)
{
segtree[root].val%=p;
return segtree[root].val;
}
int mid=(nstart+nend)/2;
pushdown(root,nstart,mid,mid+1,nend);
return (query(root*2,nstart,mid,qstart,qend)+
query(root*2+1,mid+1,nend,qstart,qend))%p;
}
void update(int root,int nstart,int nend,int ustart,int uend,int addval)
{
if (ustart>nend||uend<nstart) return ;
if (ustart<=nstart&&uend>=nend)
{
segtree[root].addmark+=addval;
segtree[root].val+=addval*(nend-nstart+1);
return ;
}
int mid=(nstart+nend)/2;
pushdown(root,nstart,mid,mid+1,nend);
if (ustart<mid) update(root*2,nstart,mid,ustart,uend,addval);
if (uend>mid) update(root*2+1,mid+1,nend,ustart,uend,addval);
segtree[root].val=(segtree[root*2].val+segtree[root*2+1].val)%p;
}
int query1(int x,int y)
{
int ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,id[top[x]],id[x]);
ans%=p;
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
ans%=p;
return ans;
}
void update1(int x,int y,int k)
{
k%=p;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],k);
}
void dfs1(int x,int f,int deep)
{
dep[x]=deep;
fa[x]=f;
siz[x]=1;
int maxn=-1;
for (int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if (y==f) continue;
dfs1(y,x,deep+1);
siz[x]+=siz[y];
if (siz[y]>maxn)
{
maxn=siz[y];
son[x]=y;
}
}
}
void dfs2(int x,int topl)
{
cnt++;
id[x]=cnt;
wt[cnt]=w[x];
top[x]=topl;
if (!son[x]) return ;
dfs2(son[x],topl);
for (int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if (y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
int main ()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin>>n>>m>>r>>p;
for (int i=1;i<=n;i++)
{
cin>>w[i];
}
for (int i=1;i<=n-1;i++)
{
int u,v;
cin>>u>>v;
add_edge(u,v);
add_edge(v,u);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,n);
for (int i=1;i<=m;i++)
{
int op;
cin>>op;
if (op==1)
{
int x,y,k;
cin>>x>>y>>k;
update1(x,y,k);
}
if (op==2)
{
int x,y;
cin>>x>>y;
cout<<query1(x,y)<<endl;
}
if (op==3)
{
int x,k;
cin>>x>>k;
update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
if (op==4)
{
int x;
cin>>x;
cout<<query(1,1,n,id[x],id[x]+siz[x]-1)<<endl;
}
}
return 0;
}