#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct sgmgent_tree{
int l,r;
int sum, tag;
}tr[maxn<<2];
int mod;
vector<int> e[maxn];
int ls(int p){return p<<1;}
int rs(int p){return p<<1|1;}
void up(int p){tr[p].sum=(tr[ls(p)].sum+tr[rs(p)].sum)%mod;}
void addtag(int p,int d){tr[p].tag+=d;tr[p].sum+=(d*(tr[p].r-tr[p].l+1))%mod;}
void pushdown(int n)
{
if(tr[n].tag)
{
addtag(ls(n),tr[n].tag);
addtag(rs(n),tr[n].tag);
tr[n].tag=0;
}
}
void addedge(int u,int v)
{
e[u].push_back(v);
e[v].push_back(u);
}
int n,m,root;
int point_w[maxn],point_new_w[maxn];
int son[maxn],id[maxn],top[maxn],deep[maxn],size[maxn],fa[maxn];
int num;
void dfs1(int x,int father)
{
deep[x]=deep[father]+1;
fa[x]=father;
size[x]=1;
for (int i=0;i<e[x].size();i++)
{
int y=e[x][i];
if(y!=father)
{
fa[y]=x;
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[son[x]]<size[y]) son[x]=y;
}
}
}
void dfs2(int x,int topx)
{
top[x]=topx;
id[x]=++num;
point_new_w[x]=point_w[x];
if(!son[x]) return;
dfs2(son[x],topx);
for (int i=0;i<e[x].size();i++)
{
int y=e[x][i];
if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
}
void build (int l,int r,int p)
{
tr[p].l=l;tr[p].r=r;
if(l==r)
{
tr[p].sum=point_new_w[l]%mod;
return;
}
int mid=(l+r)>>1;
build(l,mid,ls(p));
build(mid+1,r,rs(p));
up(p);
}
void update(int l,int r,int p,int d)
{
if(l<=tr[n].l&&tr[n].r<=r){addtag(p,d);return;}
pushdown(p);
if(tr[ls(p)].r>=l) update(l,r,ls(p),d);
if(tr[rs(p)].l<=r) update(l,r,rs(p),d);
up(p);
}
int query(int l,int r,int p)
{
if(l<=tr[p].l&&tr[p].r<=r) return tr[p].sum;
pushdown(p);
int tot=0;
if(tr[ls(p)].r>=l) tot+=query(l,r,ls(p));
if(tr[rs(p)].l<=r) tot+=query(l,r,rs(p));
return tot%mod;
}
void update_range(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
update(id[top[x]],id[x],1,z);
x=fa[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
update(id[x],id[y],1,z);
}
int query_range(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=query(id[top[x]],id[x],1);
ans%=mod;
x=fa[top[x]];
}
ans+=query(id[x],id[y],1);
return ans%mod;
}
void update_tree(int x,int k){update(id[x],id[x]+size[x]-1,1,k);}
int query_tree(int x){return query(id[x],id[x]+size[x]-1,1);}
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m>>root>>mod;
for (int i=1;i<=n;i++) cin>>point_w[i];
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
addedge(u,v);
}
dfs1(root,0);
dfs2(root,root);
build(1,n,1);
for (int i=1;i<=m;i++)
{
int opt,x,y,z;
cin>>opt>>x;
switch(opt)
{
case 1:cin>>y>>z;update_range(x,y,z);break;
case 2:cin>>y;cout<<query_range(x,y)<<endl;break;
case 3:cin>>z;update_tree(x,z);break;
case 4:cout<<query_tree(x)<<endl;break;
default:break;
}
}
return 0;
}