#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 100010;
int n;
int cnt;
int m,mod,r,x,y,z,ans,u,v,opt;
int a[maxn];
int dep[maxn],size[maxn],son[maxn],fa[maxn],top[maxn],id[maxn],wt[maxn];
struct node
{
int l,r,num,tag;
};
node tree[maxn<<2];
vector <int> val[maxn];
void dfs1(int x)
{
size[x]=1;
for(int i=0;i<val[x].size();i++)
{
int y=val[x][i];
if(!dep[y])
{
// int maxson=-1;
dep[y]=dep[x]+1;
fa[y]=x;
dfs1(y);
size[x]+=size[y];
if(size[y]>size[son[x]])
{
// maxson=size[y];
son[x]=y;
}
}
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
id[x]=++cnt;
wt[cnt]=a[x];
if(!son[x]) return ;
dfs2(son[x],tp);
for(int i=0;i<val[x].size();i++)
{
int y=val[x][i];
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
int ls(int x)
{
return x<<1;
}
int rs(int x)
{
return x<<1|1;
}
void push_up(int rt)
{
tree[rt].num=(tree[ls(rt)].num%mod+tree[rs(rt)].num%mod)%mod;
return ;
}
void push_down(int rt)
{
if(tree[rt].tag)
{
int tg=tree[rt].tag;
tree[ls(rt)].num+=((tree[ls(rt)].r-tree[ls(rt)].l+1)%mod)*tg%mod;
tree[ls(rt)].tag+=tg%mod;
tree[rs(rt)].num+=((tree[rs(rt)].r-tree[rs(rt)].l+1)%mod)*tg%mod;
tree[rs(rt)].tag+=tg%mod;
tree[ls(rt)].num%=mod;
tree[rs(rt)].num%=mod;
tree[ls(rt)].tag%=mod;
tree[rs(rt)].tag%=mod;
tree[rt].tag=0;
}
}
void build(int rt,int l,int r)
{
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].num=wt[l];
if(tree[rt].num>mod) tree[rt].num%=mod;
return ;
}
int mid=(l+r)>>1;
build(ls(rt),l,mid);
build(rs(rt),mid+1,r);
push_up(rt);
}
void add(int rt,int l,int r,int x)
{
x%=mod;
if(tree[rt].l>=l&&tree[rt].r<=r)
{
tree[rt].num+=((tree[rt].r-tree[rt].l+1)%mod)*x%mod;
tree[rt].tag+=x;
tree[rt].num%=mod;
tree[rt].tag%=mod;
return ;
}
push_down(rt);
if(tree[ls(rt)].r>=l) add(ls(rt),l,r,x);
if(tree[rs(rt)].l<=r) add(rs(rt),l,r,x);
push_up(rt);
}
void search(int rt,int l,int r)
{
if(tree[rt].l>=l&&tree[rt].r<=r)
{
ans+=tree[rt].num%mod;
ans%=mod;
return ;
}
push_down(rt);
if(tree[ls(rt)].r>=l) search(ls(rt),l,r);
if(tree[rs(rt)].l<=r) search(rs(rt),l,r);
}
void update1(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(dep[x]<dep[y]) swap(x,y);
add(1,id[top[x]],id[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,id[x],id[y],z);
}
void update2(int x,int z)
{
add(1,id[x],id[x]+size[x]-1,z);
}
void search1(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[x]<dep[y]) swap(x,y);
search(1,id[top[x]],id[x]);
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
search(1,id[x],id[y]);
ans%=mod;
}
void search2(int x)
{
search(1,id[x],id[x]+size[x]-1);
ans%=mod;
}
void debug()
{
for(int i=1;i<=n;i++) printf("i = %d num = %d tag = %d\n",i,tree[i].num,tree[i].tag);
}
void debug2()
{
for(int i=1;i<=n;i++) printf("i = %d id = %d son = %d w = %d\n",i,id[i],son[i],wt[i]);
}
int main()
{
// freopen("shupou.in","r",stdin);
scanf("%d%d%d%d",&n,&m,&r,&mod);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
val[u].push_back(v);
val[v].push_back(u);
}
dep[r]=1;
dfs1(r);
dfs2(r,r);
// debug2();
build(1,1,n);
// debug();
for(int i=1;i<=m;i++)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d%d",&x,&y,&z);
update1(x,y,z);
// debug();
}
if(opt==2)
{
scanf("%d%d",&x,&y);
ans=0;
search1(x,y);
ans%=mod;
printf("%d\n",ans);
}
if(opt==3)
{
scanf("%d%d",&x,&z);
update2(x,z);
// debug();
}
if(opt==4)
{
scanf("%d",&x);
ans=0;
search2(x);
ans%=mod;
printf("%d\n",ans);
}
}
return 0;
}