#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int>p[200005];
int vis[200005],dfn[200005],top[200005],size[200005],son[200005],d[200005],f[200005],a[200005],r[200005],b[200005];
int n,m,rr,mod,nw =0;
struct node{
int l,r,sum =0;
int lazy = 0;
void add(int x){
lazy+=x,lazy%=mod,sum= (sum+(r-l)*x)%mod;
return;
}
}tree[400005];
//---------------------------
void push_down(int k){
tree[k<<1].add(tree[k].lazy),tree[k<<1|1].add(tree[k].lazy);
tree[k].lazy = 0;
}void build(int l,int r,int k){
tree[k].l = l,tree[k].r = r;
if(l+1 == r){
// cout<<l<<' '<<b[l]<<endl;
tree[k].sum = b[l];return;
}build(l,l+r>>1,k<<1),build(l+r>>1,r,k<<1|1);
tree[k].sum = (tree[k<<1].sum+tree[k<<1|1].sum)%mod;
return;
}void upd(int l,int r,int k,int ad){
int ll = tree[k].l,rr =tree[k].r;
if(ll>=r or rr<=l)return;
if(l<=ll and rr<=r){
tree[k].add(ad);return;
}push_down(k);
upd(l,r,k<<1,ad),upd(l,r,k<<1|1,ad);
tree[k].sum = (tree[k<<1].sum+tree[k<<1|1].sum)%mod;
return;
}int query(int l,int r,int k){
// cout<<l <<' '<<r<< ' '<<tree[k].l <<' '<<tree[k].r <<' '<<k<<' '<<tree[k].sum<<endl;
int ll = tree[k].l,rr = tree[k].r;
if(ll>=r or l>=rr)return 0;
if(l<=ll and rr<=r){
return tree[k].sum;
}push_down(k);
return (query(l,r,k<<1)+query(l,r,k<<1|1))%mod;
}
//---------------------------
void dfs1(int now,int fa){
dfn[now] = ++nw,size[now] = 1,d[now] = d[fa]+1,f[now] = fa;
int mx =0;
for(int i=0;i<p[now].size();i++){
if(p[now][i]!=fa){
dfs1(p[now][i],now);
size[now]+=size[p[now][i]];
if(mx<size[p[now][i]]){
mx =size[p[now][i]],son[now] = p[now][i];
}
}
}return;
}void dfs2(int now,int fa,int ok){
dfn[now] = ++nw;
if(ok)top[now] = top[fa];
r[now] = dfn[now];
for(int i=0;i<p[now].size();i++){
if(p[now][i] == son[now])dfs2(p[now][i],now,1),r[now] = max(r[now],r[p[now][i]]);
}for(int i =0;i<p[now].size();i++){
if(p[now][i]!=son[now] and p[now][i]!=fa)dfs2(p[now][i],now,0),r[now] = max(r[now],r[p[now][i]]);
}return;
}void upd1(int x,int y,int add){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
upd(dfn[top[x]],dfn[x]+1,1,add);
x = f[top[x]];
}if(d[x]<d[y])swap(x,y);
upd(dfn[y],dfn[x]+1,1,add);
}int query1(int x,int y){
int res =0;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
res = (res+query(dfn[top[x]],dfn[x]+1,1))%mod;
x = f[top[x]];
}if(d[x]<d[y])swap(x,y);
res+=query(dfn[y],dfn[x]+1,1);
return res;
}void upd2(int x,int add){
int xx= query(dfn[x],r[x]+1,1);
//cout << dfn[x] << " " << r[x]+1 <<" " << xx << endl;
upd(dfn[x],r[x]+1,1,add);
// cout<<query(3,4,1)<<endl;
}int query2(int x){
int xx= query(dfn[x],r[x]+1,1);
//cout << dfn[x] << " " << r[x]+1 <<" " << xx << endl;
//cout<<query(3,4,1)<<endl;
return query(dfn[x],r[x]+1,1);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m >> rr >> mod;
for(int i=1;i<=n;i++)cin >> a[i];
for(int i=1;i<n;i++){
int a,b;cin >> a >> b;
p[a].push_back(b),p[b].push_back(a);
}dfs1(rr,rr);
memset(dfn,-1,sizeof(dfn));
for(int i=1;i<=n;i++)top[i] = i;
nw = 0;
dfs2(rr,rr,0);
for(int i=1;i<=n;i++){
b[dfn[i]] = a[i];
}//for(int i=1;i<=n;i++)cout << b[i] << " ";
//cout << endl;
build(1,n+1,1);
//cout<<query(3,4,1)<<endl;
while(m--){
int s;
cin >> s;
if(s == 1){
int a,b,c;cin>> a >> b >> c;
upd1(a,b,c);
}if(s == 2){
int a,b;cin >> a>> b;
cout << query1(a,b) << '\n';
}if(s == 3){
int x,y;cin>> x >> y;
upd2(x,y);
}if(s == 4){
int x;cin>> x;
cout << query2(x) << '\n';
}
}return 0;
}
1 x y z,表示将树从 x 到 y 结点最短路径上所有节点的值都加上 z。
2 x y,表示求树从 x 到 y 结点最短路径上所有节点的值之和。
3 x z,表示将以 x 为根节点的子树内所有节点值都加上 z。
4 x 表示求以 x 为根节点的子树内所有节点值之和