#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int mod=1000000007;
const int inf=1000000000;
const int maxn=100000;
const int maxm=1000000;
int n,m,r,p;
int val[maxn+10];
int to[maxn*2+10];
int next[maxn*2+10];
int head[maxn+10],cnt;
int depth[maxn+10];//节点深度
int siz[maxn+10];//节点子树大小
int son[maxn+10];//有子节点的节点重儿子编号,没有为0
int fa[maxn+10];//父亲节点编号
void dfs1(int x,int f,int d)
{
fa[x]=f;
depth[x]=d;
for(int i=head[x];i!=-1;i=next[i])
{
int l=to[i];
if(l!=f)
{
dfs1(l,x,d+1);
siz[x]+=siz[l];
if(son[x]==0||siz[l]>siz[son[x]])
son[x]=l;
}
}
siz[x]++;
}
int id[maxn+10],num;//原编号到dfs序的映射
int wt[maxn+10];//由dfs序得到节点权重
int top[maxn+10];//链顶端的编号
//dfs序只和id、wt数组有关,其余数组涉及的都是原编号,线段树部分完全用的是dfs序
void dfs2(int x,int topf)
{
id[x]=num++;
wt[id[x]]=val[x];
top[x]=topf;
if(son[x]==0)
return;
dfs2(son[x],topf);
for(int i=head[x];i!=-1;i=next[i])
{
int l=to[i];
if(l!=fa[x]&&son[x]!=l)
dfs2(l,l);
}
}
void init()
{
cnt=0;
num=1;
memset(head,-1,sizeof(head));
memset(siz,0,sizeof(siz));
memset(son,0,sizeof(son));
}
/*****以下是线段树部分(注意Tag的写法哦)*****/
struct ttree
{
int l,r;
int tag;
int sum;
inline int len()
{
return r-l+1;
}
};
ttree tree[maxn*4+10];
void pushup(int x)
{
if(tree[x].l==tree[x].r)
return;
tree[x].sum=(tree[x*2].sum+tree[x*2+1].sum)%p;
}
void pushdown(int x)
{
if(tree[x].l==tree[x].r)
return;
int tag=tree[x].tag;
tree[x].tag=0;
tree[x*2].tag+=tag;
tree[x*2+1].tag+=tag;
tree[x*2].sum=(tree[x*2].sum+tag*tree[x*2].len())%p;
tree[x*2+1].sum=(tree[x*2+1].sum+tag*tree[x*2+1].len())%p;
}
void build(int x,int l,int r)
{
tree[x].l=l;
tree[x].r=r;
tree[x].tag=0;
if(tree[x].l==tree[x].r)
tree[x].sum=wt[tree[x].l];//wt数组的
else
{
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
pushup(x);
}
}
void modify(int x,int l,int r,int op)
{
if(l<=tree[x].l&&r>=tree[x].r)
{
tree[x].tag+=op;
tree[x].sum=(tree[x].sum+op*tree[x].len())%p;
}
else
{
pushdown(x);
int mid=(tree[x].l+tree[x].r)/2;
if(l<=mid)
modify(x*2,l,r,op);
if(r>=mid+1)
modify(x*2+1,l,r,op);
pushup(x);
}
}
int query(int x,int l,int r)
{
if(l<=tree[x].l&&r>=tree[x].r)
return tree[x].sum;
else
{
pushdown(x);
int res=0;
int mid=(tree[x].l+tree[x].r)/2;
if(l<=mid)
res=(res+query(x*2,l,r))%p;
if(r>=mid+1)
res=(res+query(x*2+1,l,r))%p;
return res;
}
}
/*****以上是线段树部分*****/
int qrange(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])
std::swap(x,y);
int res=query(1,id[top[x]],id[x]);
ans=(ans+res)%p;
x=fa[top[x]];
}
if(depth[x]<depth[y])
std::swap(x,y);
int res=query(1,id[y],id[x]);
ans=(ans+res)%p;
return ans;
}
void updrange(int x,int y,int z)
{
z%=p;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])
std::swap(x,y);
modify(1,id[top[x]],id[x],z);
x=fa[top[x]];
}
if(depth[x]<depth[y])
std::swap(x,y);
modify(1,id[y],id[x],z);
}
int qson(int x)
{
return query(1,id[x],id[x]+siz[x]-1);
}
void updson(int x,int z)
{
modify(1,id[x],id[x]+siz[x]-1,z);
}
int main()
{
init();
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++)
scanf("%d",val+i);
for(int i=1,a,b;i<n;i++)
{
scanf("%d%d",&a,&b);
to[cnt]=b;next[cnt]=head[a];head[a]=cnt++;
to[cnt]=a;next[cnt]=head[b];head[b]=cnt++;
}
dfs1(r,-1,1);
dfs2(r,r);
build(1,1,n);
while(m--)
{
int op,x,y,z;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&z);
updrange(x,y,z);
}
if(op==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",qrange(x,y));
}
if(op==3)
{
scanf("%d%d",&x,&z);
updson(x,z);
}
if(op==4)
{
scanf("%d",&x);
printf("%d\n",qson(x));
}
}
return 0;
}