#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
#define ll long long
ll inline read()
{
ll num=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){num=(num<<3)+(num<<1)+(ch^48);ch=getchar();}
return num*f;
}
int n,m,rt;ll mod,a[N],w[N];
ll add(ll x,ll y){return x+y>=mod?x+y-mod:x+y;}
ll dec(ll x,ll y){return x-y<0?x-y+mod:x-y;}
struct edge{int u,v,nxt;}e[N<<1];
int cnt,head[N];
void add(int u,int v){e[++cnt]=(edge){u,v,head[u]};head[u]=cnt;}
int tim,siz[N],fa[N],dep[N],son[N],id[N],top[N];
struct Segment_Tree
{
ll t[N<<2],tag[N<<2];
void up(int k){t[k]=add(t[k<<1],t[k<<1|1]);}
void build(int k,int l,int r)
{
if(l==r){t[k]=a[l];return;}
int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
up(k);
}
void LT(int k,int l,int r,ll v){t[k]+=1ll*(r-l+1)*v;tag[k]+=v;}
void down(int k,int l,int r)
{
if(!tag[k])return;
int mid=l+r>>1;
LT(k<<1,l,mid,tag[k]);
LT(k<<1|1,mid+1,r,tag[k]);
tag[k]=0;
}
void upd(int k,int l,int r,int ql,int qr,ll v)
{
if(ql<=l&&r<=qr){LT(k,l,r,v);return;}
down(k,l,r);
int mid=l+r>>1;
if(ql<=mid)upd(k<<1,l,mid,ql,qr,v);
if(qr>mid)upd(k<<1|1,mid+1,r,ql,qr,v);
up(k);
}
ll ask(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return t[k];
down(k,l,r);
int mid=l+r>>1;ll res=0;
if(ql<=mid)res=add(res,ask(k<<1,l,mid,ql,qr));
if(qr>mid)res=add(res,ask(k<<1|1,mid+1,r,ql,qr));
return res;
}
}Tree;
void UpdPath(int u,int v,ll w)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
Tree.upd(1,1,n,id[top[u]],id[u],w);
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
Tree.upd(1,1,n,id[u],id[v],w);
}
ll AskPath(int u,int v)
{
ll res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
res=add(res,Tree.ask(1,1,n,id[top[u]],id[u]));
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
res=add(res,Tree.ask(1,1,n,id[u],id[v]));
return res;
}
void UpdSubtree(int u,ll w){Tree.upd(1,1,n,id[u],id[u]+siz[u]-1,w);}
ll AskSubtree(int u){return Tree.ask(1,1,n,id[u],id[u]+siz[u]-1);}
void dfs(int u)
{
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[u])continue;
fa[v]=u;dep[v]=dep[u]+1;
dfs(v);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs(int u,int tid)
{
id[u]=++tim;a[tim]=w[u];top[u]=tid;
if(!son[u])return;
dfs(son[u],tid);
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[u]||v==son[u])continue;
dfs(v,v);
}
}
int main(){
n=read();m=read();rt=read();mod=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1,u,v;i<n;i++)u=read(),v=read(),add(u,v),add(v,u);
dep[0]=-1;dfs(rt);dfs(rt,rt);
Tree.build(1,1,n);
while(m--)
{
int op;op=read();
if(op==1)
{
int x,y;ll w;
x=read();y=read();w=read();
UpdPath(x,y,w);
}
if(op==2)
{
int x,y;
x=read();y=read();
printf("%lld\n",AskPath(x,y));
}
if(op==3)
{
int x;ll w;
x=read();w=read();
UpdSubtree(x,w);
}
if(op==4)
{
int x;
x=read();
printf("%lld\n",AskSubtree(x));
}
}
return 0;
}