#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <iostream>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int N,M,R,P;
int deep[maxn],F[maxn],size_[maxn],son[maxn];//深度,父亲节点,子树大小,重儿子
vector<int> G[maxn];
void dfs1(int x,int f)
{
int son_zhong=0,son_num=0;
size_[x]=1;
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(v==f)
continue;
F[v]=x;
deep[v]=deep[x]+1;
dfs1(v, x);
size_[x]+=size_[v];
if(son_num<size_[v])
{
son_num=size_[v];
son_zhong=v;
}
}
son[x]=son_zhong;
}
int id[maxn],id_inv[maxn],wt[maxn],w[maxn],top[maxn];
int cnt;
void dfs2(int x,int topt)
{
id[x]=++cnt;
top[id[x]]=topt;
wt[id[x]]=w[x];
if(son[x]!=0)
dfs2(son[x], topt);
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(v==F[x]||v==son[x])
continue;
dfs2(v, v);
}
}
//区间查询 区间更新线段树
ll tree[maxn<<2],lazy[maxn<<2];
void pushdown(int rt,int l,int r){
lazy[lson]=(lazy[lson]+lazy[rt])%P;
lazy[rson]=(lazy[rson]+lazy[rt])%P;
int mid=(l+r)/2;
tree[lson]=(tree[lson]+lazy[rt]*(mid-l+1))%P;
tree[rson]=(tree[rson]+lazy[rt]*(r-mid))%P;
lazy[rt]=0;
}
void pushup(int rt)
{
tree[rt]=(tree[lson]+tree[rson])%P;
}
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt]=wt[l];
return;
}
int mid=(l+r)/2;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void update(int x,int L,int R,int l,int r,int rt)
{
pushdown(rt, l, r);
if(L<=l&&r<=R)
{
tree[rt]=(tree[rt]+(r-l+1)*x);
lazy[rt]=(x)%P;
return;
}
int mid=(l+r)/2;
if(mid>=L)
update(x, L, R, l,mid,lson);
if(mid<R)
update(x, L, R, mid+1,r,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
pushdown(rt,l,r);
if(L<=l&&r<=R)
{
return tree[rt];
}
int mid=(r+l)/2;
ll ans=0;
if(mid>=L)
ans=(ans+query(L, R, l,mid,lson))%P;
if(mid<R)
ans=(ans+query(L, R, mid+1,r,rson))%P;
return ans;
}
int main()
{
cin>>N>>M>>R>>P;
for(int i=1;i<=N;i++)
cin>>w[i];
for(int i=0;i<N-1;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(R, R);
dfs2(R, R);
for(int i=1;i<=N;i++)
id_inv[id[i]]=i;
build(1, 1, N);
for(int i=0;i<M;i++)
{
int flag;
cin>>flag;
if(flag==1)
{
int x,y,z;
cin>>x>>y>>z;
x=id[x];
y=id[y];
while(1)
{
if(deep[top[x]]<deep[top[y]])
swap(x, y);
if(top[x]==top[y])
{
if(x<y)
swap(x, y);
update(z, y, x, 1, N, 1);
break;
}
else
{
update(z, id[top[x]], x, 1, N, 1);
x=id[F[top[x]]];
}
}
}
else if(flag==2)
{
int x,y;
cin>>x>>y;
x=id[x];
y=id[y];
ll ans=0;
while(1)
{
if(deep[top[x]]<deep[top[y]])
swap(x, y);
if(top[x]==top[y])
{
if(x<y)
swap(x, y);
ans=(ans+query( y, x, 1, N, 1))%P;
break;
}
else
{
ans=(ans+query(id[top[x]], x, 1, N, 1))%P;
x=id[F[top[x]]];
}
}
cout<<ans<<endl;
}
else if(flag==3)
{
int x,z;
cin>>x>>z;
update(z, id[x], id[x]+size_[x]-1, 1, N, 1);
}
else if(flag==4)
{
int x;
cin>>x;
cout<<query(id[x], id[x]+size_[x]-1, 1, N, 1)<<endl;
}
}
}