#include<bits/stdc++.h>
using namespace std;
int n,m,r,mod;
int u,v;
int op,x,y,z;
vector<int> adj[100010],son[100010];
vector<long long> a;
int b[100010];
bool vis[100010];
int des[100010],deep[100010],dss[100010];
int hld[100010],hfa[100010],hff[100010];
int k;
bool cmpdes(int a,int b) {
return des[a]>des[b];
}
int dfs1(int p) {
int res=1;
for(int i:adj[p]) {
if(vis[i]) {
continue;
}
vis[i]=1;
son[p].push_back(i);
res+=dfs1(i);
}
return des[p]=res;
}
void HLD(int p,int fa) {
if(p==r) {
hff[1]=1;
}
hld[p]=++k;
a.push_back(b[p]);
hfa[k]=hld[fa];
sort(son[p].begin(),son[p].end(),cmpdes);
for(int i=0; i<son[p].size(); i++) {
if(i==0) {
HLD(son[p][i],fa);
} else {
hff[k+1]=hld[p];
HLD(son[p][i],son[p][i]);
}
}
return ;
}
int dfs2(int p,int d) {
int res=hld[p];
deep[hld[p]]=d;
for(int i:son[p]) {
res=max(res,dfs2(i,d+1));
}
return dss[hld[p]]=res;
}
struct Segtree {
int n;
vector<long long> tree,lazy;
void init(int size,vector<long long> &a) {
n=size;
tree.resize(4*n+10);
lazy.resize(4*n+10);
build(1,1,n,a);
}
void build(int p,int l,int r,vector<long long> &a) {
if(l==r) {
tree[p]=a[l-1];
return;
}
int mid=(l+r)/2;
build(p*2,l,mid,a);
build(p*2+1,mid+1,r,a);
tree[p]=(tree[p*2]+tree[p*2+1])%mod;
}
void pushdown(int p,int l,int r) {
if(lazy[p]) {
int mid=(l+r)/2;
tree[p*2]+=(mid-l+1)*lazy[p];
tree[p*2]%=mod;
tree[p*2+1]+=(r-mid)*lazy[p];
tree[p*2+1]%=mod;
lazy[p*2]+=lazy[p];
lazy[p*2]%=mod;
lazy[p*2+1]+=lazy[p];
lazy[p*2+1]%=mod;
lazy[p]=0;
}
}
void add(int p,int l,int r,int ql,int qr,long long val) {
if(ql<=l && r<=qr) {
tree[p]+=(r-l+1)*val;
tree[p]%=mod;
lazy[p]+=val;
lazy[p]%=mod;
return;
}
pushdown(p,l,r);
int mid=(l+r)/2;
if(mid>=ql) {
add(p*2,l,mid,ql,qr,val);
}
if(mid+1<=qr) {
add(p*2+1,mid+1,r,ql,qr,val);
}
tree[p]=(tree[p*2]+tree[p*2+1])%mod;
}
long long query(int p,int l,int r,int ql,int qr) {
if(ql<=l && r<=qr) {
return tree[p];
}
pushdown(p,l,r);
int mid=(l+r)/2;
long long res=0;
if(mid>=ql) {
res+=query(p*2,l,mid,ql,qr);
res%=mod;
}
if(mid+1<=qr) {
res+=query(p*2+1,mid+1,r,ql,qr);
res%=mod;
}
return res;
}
} tree;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>r>>mod;
for(int i=1; i<=n; i++) {
cin>>b[i];
}
for(int i=1; i<n; i++) {
cin>>u>>v;
adj[u].push_back(v);
adj[v].push_back(u);
}
vis[r]=1;
dfs1(r);
HLD(r,r);
dfs2(r,1);
tree.init(n,a);
for(int i=1; i<=m; i++) {
cin>>op;
if(op==1) {
cin>>x>>y>>z;
x=hld[x];
y=hld[y];
while(hfa[x]!=hfa[y]) {
if(deep[hfa[x]]<deep[hfa[y]]) {
swap(x,y);
}
tree.add(1,1,n,x,hfa[x],z);
x=hff[hfa[x]];
}
tree.add(1,1,n,min(x,y),max(x,y),z);
}
if(op==2) {
long long tot=0;
cin>>x>>y;
x=hld[x];
y=hld[y];
while(hfa[x]!=hfa[y]) {
if(deep[hfa[x]]<deep[hfa[y]]) {
swap(x,y);
}
tot+=tree.query(1,1,n,x,hfa[x]);
tot%=mod;
x=hff[hfa[x]];
}
tot+=tree.query(1,1,n,min(x,y),max(x,y));
cout<<tot%mod<<'\n';
}
if(op==3) {
cin>>x>>z;
x=hld[x];
tree.add(1,1,n,x,dss[x],z);
}
if(op==4) {
cin>>x;
x=hld[x];
cout<<tree.query(1,1,n,x,dss[x])<<'\n';
}
}
return 0;
}