#include<cstdio>
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<set>
#define int long long
using namespace std;
int mod;
int head[100005];
int dep[100005];
int size[100005], son[100005], id[100005];
int top[100005], a[100005];
int sum[400005], tag[400005];
int f[100005];
int w[100005];
int n, m, r, p;
struct Node{
int next, v;
};
int nw[100005];
Node edge[200005];
int tot = 0;
void add_edge(int u, int v){
tot++;
edge[tot].next = head[u];
edge[tot].v = v;
head[u] = tot;
}
void dfs1(int u, int fa){
f[u] = fa;
dep[u] = dep[fa] + 1;
size[u] = 1;
int maxs = 0;
for(int i = head[u]; i; i = edge[i].next){
int v = edge[i].v;
if(v == fa){
continue;
}
dfs1(v, u);
size[u] += size[v];
if(size[v] > maxs){
son[u] = v;
maxs = size[v];
}
}
return;
}
void dfs2(int u, int topp){
tot++;
id[u] = tot;
w[tot] = a[u];
top[u] = topp;
if(son[u] == 0){
return;
}
dfs2(son[u], topp);
for(int i = head[u]; i; i = edge[i].next){
int v = edge[i].v;
if(v == f[u] || v == son[u]){
continue;
}
dfs2(v, v);
}
}
int lc(int p){
return (p * 2);
}
int rc(int p){
return (p * 2 + 1);
}
void push_up(int p){
sum[p] = (sum[lc(p)] + sum[rc(p)]) % mod;
}
void push_down(int p, int l, int r){
int mid = (l + r) / 2;
sum[lc(p)] = (sum[lc(p)] + (mid - l + 1) * tag[p] % mod) % mod;
sum[rc(p)] = (sum[rc(p)] + (r - mid) * tag[p] % mod) % mod;
tag[lc(p)] = (tag[lc(p)] + tag[p]) % mod;
tag[rc(p)] = (tag[p] + tag[rc(p)]) % mod;
tag[p] = 0;
return;
}
int query(int p, int l, int r, int ql, int qr){
if(l > qr || r < ql){
return 0;
}
if(l >= ql && r <= qr){
return sum[p];
}
push_down(p, l, r);
int mid = (l + r) / 2;
return (query(lc(p), l, mid, ql, qr) + query(rc(p), mid + 1, r, ql, qr)) % mod;
}
void update(int p, int l, int r, int ql, int qr, int t){
if(l > qr || r < ql){
return;
}
if(l >= ql && r <= qr){
sum[p] = (sum[p] + t * (r - l + 1) % mod) % mod;
tag[p] = (tag[p] + t) % mod;
return;
}
int mid = (l + r) / 2;
push_down(p, l, r);
update(lc(p), l, mid, ql, qr, t);
update(rc(p), mid + 1, r, ql, qr, t);
push_up(p);
return;
}
void build(int p, int l, int r){
if(l == r){
sum[p] = w[l];
return;
}
int mid = (l + r) / 2;
build(lc(p), l, mid);
build(rc(p), mid + 1, r);
push_up(p);
}
int qtrack(int x, int y){
int ans = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans = (ans + query(1, 1, n, id[top[x]], id[x])) % mod;
x = f[top[x]];
}
if(dep[x] > dep[y]){
swap(x, y);
}
ans = (ans + query(1, 1, n, id[x], id[y])) % mod;
return ans;
}
void track_up(int x, int y, int t){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, id[top[x]], id[x], t);
x = f[top[x]];
}
if(dep[x] > dep[y]){
swap(x, y);
}
update(1, 1, n, id[x], id[y], t);
return;
}
signed main(){
cin >> n >> m >> r >> mod;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
for(int i = 1; i <= n - 1; i++){
int u, v;
cin >> u >> v;
add_edge(u, v);
add_edge(v, u);
}
dfs1(r, 0);
tot = 0;
dfs2(r, r);
build(1, 1, n);
for(int i = 0; i < m; i++){
int op;
cin >> op;
if(op == 1){
int x, y, z;
cin >> x >> y >> z;
track_up(x, y, z);
} else if(op == 2){
int x, y;
cin >> x >> y;
cout << qtrack(x, y) << endl;
} else if(op == 3){
int x, z;
cin >> x >> z;
int l = id[x];
int r = id[x] + size[x] - 1;
update(1, 1, n, l, r, z);
} else if(op == 4){
int x;
cin >> x;
int l = id[x];
int r = id[x] + size[x] - 1;
cout << query(1, 1, n, l, r) << endl;
}
}
return 0;
}