#include<bits/stdc++.h>
#define gc getchar()
#define pc putchar
#define N 200100
#define Rg register
#define ll long long
#define lson(x) x<<1
#define rson(x) x<<1|1
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
inline int lowbit(int x){return x&(-x);}
template<typename T>
inline void read(T &x)
{
x=0;bool f=1;
char c=gc;
while(!isdigit(c)){if(c=='-')f=0;c=gc;}
while(isdigit(c))
x=(x<<1)+(x<<3)+(c-'0'),
c=gc;
x=f?x:-x;
return ;
}
template<typename T>
void write(T x)
{
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
return ;
}
int n,m,root,MOD,a[N];
int dep[N],fa[N],siz[N],son[N],w[N],top[N],dfsx[N];
ll s[N<<2],lazy[N<<2],ans;
struct node
{
int to,nxt;
}edge[N];int head[N],cnt,cntx;
inline void add(int u,int v)
{
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
return ;
}
inline void pushdown(int u,int len)
{
lazy[lson(u)]+=lazy[u];
lazy[rson(u)]+=lazy[u];
s[lson(u)]+=lazy[u]*(len-(len>>1));
s[rson(u)]+=lazy[u]*(len>>1);
s[lson(u)]%=MOD;s[rson(u)]%=MOD;
lazy[u]=0;
return ;
}
inline void query(int u,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{(ans+=s[u])%=MOD;return ;}
else
{
int mid=l+r>>1;
if(lazy[u]) pushdown(u,r-l+1);
if(L<=mid) query(lson(u),l,mid,L,R);
if(R>mid) query(rson(u),mid+1,r,L,R);
}
return ;
}
inline void update(int u,int l,int r,int L,int R,int k)
{
if(L<=l&&r<=R)
lazy[u]+=k,s[u]+=(r-l+1)*k;
else
{
int mid=l+r>>1;
if(lazy[u]) pushdown(u,r-l+1);
if(L<=mid) update(lson(u),l,mid,L,R,k);
if(R>mid) update(rson(u),mid+1,r,L,R,k);
s[u]=(s[lson(u)]+s[rson(u)])%MOD;
}
return ;
}
inline void change1(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,dfsx[top[x]],dfsx[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,dfsx[x],dfsx[y],z);
return ;
}
inline void change2(int x,int k)
{
update(1,1,n,dfsx[x],dfsx[x]+siz[x]-1,k);
return ;
}
inline int query1(int x,int y)
{
int res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=0;
query(1,1,n,dfsx[top[x]],dfsx[x]);
(res+=ans)%=MOD;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=0;
query(1,1,n,dep[x],dep[y]);
(res+=ans)%=MOD;
return res;
}
inline int query2(int x)
{
ans=0;
query(1,1,n,dfsx[x],dfsx[x]+siz[x]-1);
return ans;
}
void dfs1(int u,int f,int d)
{
dep[u]=d;fa[u]=f;siz[u]=1;
int Max=-1;
for(Rg int i=head[u];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==f) continue;
dfs1(to,u,d+1);
siz[u]+=siz[to];
if(siz[to]>Max) son[u]=to,Max=siz[to];
}
return ;
}
void dfs2(int u,int t)
{
cntx++;dfsx[u]=cntx;
w[cntx]=a[u];top[u]=t;
if(!son[u]) return ;
dfs2(son[u],t);
for(Rg int i=head[u];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fa[u]||to==son[u]) continue;
dfs2(to,to);
}
return ;
}
void build(int u,int l,int r)
{
if(l==r){s[u]=w[l]%MOD;return ;}
int mid=l+r>>1;
build(lson(u),l,mid);
build(rson(u),mid+1,r);
s[u]=(s[lson(u)]+s[rson(u)])%MOD;
return ;
}
int main()
{
read(n);read(m);read(root);read(MOD);
for(Rg int i=1;i<=n;i++) read(a[i]);
for(Rg int i=1;i<n;i++)
{
int x,y;
read(x);read(y);
add(x,y);add(y,x);
}
dfs1(root,0,1);
dfs2(root,root);
build(1,1,n);
while(m--)
{
int op,x,y,z;read(op);
if(op==1)
{
read(x);read(y);read(z);
z%=MOD;change1(x,y,z);
}
if(op==2)
{
read(x);read(y);
write(query1(x,y));puts("");
}
if(op==3)
{
read(x);read(y);
change2(x,y);
}
if(op==4)
{
read(x);
write(query2(x));puts("");
}
}
return 0;
}