#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define rt 1,n,1
#define ls now<<1
#define rs now<<1|1
#define lson l,mid,ls
#define rson mid+1,r,rs
struct edge{
int u,v,next;
}e[maxn];
struct node{
int f,d,s,son,rk,top,w,maxid;
}N[maxn];
// f父节点 d深度 s节点合数 son重儿子 top重链的头节点 w点权
// maxid 以此点为根的节点里dfs序最大的序
// rk dfs序
int head[maxn],id[maxn],v[maxn],tot=0;
// id dfs序
// v N[id[i]].w
int tree[maxn*4],lazy[maxn*4],mod;
int n,m,r;
void creatEdge(int u,int v)
{
e[++tot]=(edge){u,v,head[u]};
head[u]=tot;
}
// f d s
void dfs1(int u,int fa,int dep)
{
N[u].f=fa;
N[u].d=dep;
N[u].s=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==u||N[v].d) continue;
dfs1(v,u,dep+1);
N[u].s+=N[v].s;
if(N[v].s>N[N[u].son].s)
N[u].son=v;
}
}
int mub=0;
// top id rk maxid;
void dfs2(int u,int fa,int t)
{
N[u].top=t;
id[u]=++mub;
v[mub]=N[u].w;
N[u].maxid=mub;
if(!N[u].son) return ;
dfs2(N[u].son,u,t);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==N[u].son||v==fa||N[v].d!=N[u].d+1) continue;
dfs2(v,u,v);
}
N[u].maxid=mub;
}
void built(int l,int r,int now)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[now]=v[l];
return ;
}
built(lson);
built(rson);
tree[now]=tree[ls]+tree[rs];
tree[now]%=mod;
}
void pushdown(int l,int r,int now)
{
int mid=(l+r)>>1;
lazy[ls]+=lazy[now];
lazy[rs]+=lazy[now];
lazy[ls]%=mod;
lazy[rs]%=mod;
tree[ls]+=(mid-l+1)*lazy[now];
tree[rs]+=(r-mid)*lazy[now];
tree[ls]%=mod;
tree[rs]%=mod;
lazy[now]=0;
}
void updata(int l,int r,int now,int left,int right,int k)
{
int mid=(l+r)>>1;
if(left<=l&&r<=right)
{
tree[now]+=(r-l+1)*k;
lazy[now]+=k;
tree[now]%=mod;
lazy[now]%=mod;
return ;
}
if(lazy[now])
pushdown(l,r,now);
if(left<=mid) updata(lson,left,right,k);
if(right>mid) updata(rson,left,right,k);
tree[now]=tree[ls]+tree[rs];
tree[now]%=mod;
}
void cmd1(int x,int y,int k)
{
int fx=N[x].top,fy=N[y].top;
while(fx!=fy)
{
if(N[fx].d>=N[fy].d)
{
updata(rt,id[fx],id[x],k);
x=N[fx].f;
fx=N[x].top;
}
else
{
updata(rt,id[fy],id[y],k);
y=N[fy].f;
fy=N[y].top;
}
}
if(id[x]<=id[y])
updata(rt,id[x],id[y],k);
else
updata(rt,id[y],id[x],k);
}
int query(int l,int r,int now,int left,int right)
{
int mid=(l+r)>>1;
if(left<=l&&r<=right)
{
return tree[now];
}
if(lazy[now])
pushdown(l,r,now);
int ans=0;
if(left<=mid) ans+=query(lson,left,right);
if(right>mid) ans+=query(rson,left,right);
tree[now]=tree[ls]+tree[rs];
tree[now]%=mod;
ans%=mod;
return ans;
}
int cmd2(int x,int y)
{
int fx=N[x].top,fy=N[y].top;
int ans=0;
while(fx!=fy)
{
if(N[fx].d>=N[fy].d)
{
ans+=query(rt,id[fx],id[x]);
x=N[fx].f,fx=N[x].top;
}
else
{
ans+=query(rt,id[fy],id[y]);
y=N[fy].f,fy=N[y].top;
}
}
ans%=mod;
if(id[x]<=id[y])
ans+=query(rt,id[x],id[y]);
else
ans+=query(rt,id[y],id[x]);
ans%=mod;
return ans;
}
void cmd3(int x,int k)
{
updata(rt,id[x],N[x].maxid,k);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&r,&mod);
for(int i=1;i<=n;i++)
scanf("%d",&N[i].w);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
creatEdge(u,v);
creatEdge(v,u);
}
dfs1(r,r,1);
dfs2(r,0,r);
built(rt);
while(m--)
{
int cmd,x,y,z;
scanf("%d%d",&cmd,&x);
if(cmd==1)
{
scanf("%d%d",&y,&z);
cmd1(x,y,z);
}
if(cmd==2)
{
scanf("%d",&y);
printf("%d\n",cmd2(x,y));
}
if(cmd==3)
{
scanf("%d",&z);
cmd3(x,z);
}
if(cmd==4)
{
printf("%d\n",query(rt,id[x],N[x].maxid));
}
// cout<<"end"<<endl;
}
return 0;
}