rt
#include<iostream>
#include<vector>
#define int long long
#define pushup(p) tree[p] = tree[p*2]+tree[p*2+1]
using namespace std;
int tree[1000010],mark[1000010],a[1000010],dfn[1000010],rk[1000010],fa[1000010],son[1000010],deep[1000010],top[1000010],sz[1000010],n,m,r,p1,opt,x,y,z,k,cur;
vector<int> E[1000010];
void pushdown(int p,int l,int r)
{
mark[p*2]+=mark[p];
mark[p*2+1]+=mark[p];
tree[p*2]+=mark[p]*((l+r)/2*1ll-l+1);
tree[p*2]%=p1;
tree[p*2+1]+=mark[p]*(r-(l+r)/2*1ll);
tree[p*2+1]%=p1;
mark[p] = 0;
}
void build(int l,int r,int p)
{
if(l == r) tree[p] = a[rk[l]];
else
{
build(l,(l+r)/2*1ll,p*2);
build(((l+r)/2+1)*1ll,r,p*2+1);
pushup(p);
}
}
void add(int l,int r,int cl,int cr,int p,int d)
{
if(l > cr||r < cl) return;
else if(l >= cl&&r <= cr)
{
tree[p]+=d*(r-l+1);
tree[p]%=p1;
mark[p]+=d;
}
else
{
pushdown(p,l,r);
add(l,(l+r)/2*1ll,cl,cr,p*2,d);
add(((l+r)/2+1)*1ll,r,cl,cr,p*2+1,d);
pushup(p);
}
}
int query(int l,int r,int cl,int cr,int p)
{
if(l > cr||r < cl) return 0;
else if(l >= cl&&r <= cr)
{
return tree[p]%p1;
}
else
{
pushdown(p,l,r);
return query(l,(l+r)/2*1ll,cl,cr,p*2)%p1+query(((l+r)/2+1)*1ll,r,cl,cr,p*2+1)%p1;
}
}
void dfs1(int now)
{
dfn[now] = ++cur;
rk[cur] = now;
deep[now] = deep[fa[now]]+1;
sz[now]++;
for(auto v:E[now])
{
if(v == fa[now])
{
continue;
}
fa[v] = now;
dfs1(v);
sz[now]+=sz[v];
if(!son[now]||sz[v] > sz[son[now]])
{
son[now] = v;
}
}
}
void dfs2(int now,int tv)
{
top[now] = tv;
if(son[now])
{
dfs2(son[now],tv);
}
for(auto v:E[now])
{
if(v == son[now]||v == fa[now])
{
continue;
}
dfs2(v,v);
}
}
void modifyontree(int u,int v,int d)
{
while(top[u] != top[v])
{
if(deep[top[u]] < deep[top[v]])
{
swap(u,v);
}
add(1,n,dfn[top[u]],dfn[u],1,d);
u = fa[top[u]];
}
if(deep[u] > deep[v])
{
swap(u,v);
}
add(1,n,dfn[u],dfn[v],1,d);
}
int queryontree(int u,int v)
{
int ret = 0;
while(top[u] != top[v])
{
if(deep[top[u]] < deep[top[v]])
{
swap(u,v);
}
ret+=query(1,n,dfn[top[u]],dfn[u],1);
ret%=p1;
u = fa[top[u]];
}
if(deep[u] > deep[v])
{
swap(u,v);
}
ret+=query(1,n,dfn[u],dfn[v],1);
ret%=p1;
return ret;
}
#undef int
int main()
{
cin>>n>>m>>r>>p1;
for(int i = 1;i <= n;i++)
{
cin>>a[i];
}
for(int i = 1;i <= n-1;i++)
{
cin>>x>>y;
E[x].push_back(y);
E[y].push_back(x);
}
dfs1(r);
dfs2(r,r);
build(1,n,1);
for(int i = 1;i <= m;i++)
{
cin>>opt;
if(opt == 1)
{
cin>>x>>y>>z;
modifyontree(x,y,z);
}
else if(opt == 2)
{
cin>>x>>y;
cout<<queryontree(x,y)%p1;
}
else if(opt == 3)
{
cin>>x>>z;
add(1,n,dfn[x],dfn[x]+sz[x]-1,1,z);
}
else if(opt == 4)
{
cin>>x;
cout<<query(1,n,dfn[x],dfn[x]+sz[x]-1,1)%p1<<endl;
}
}
}