#include<iostream>
#define int long long
using namespace std;
const int N = 1E5 + 10;
struct Edge {
int v;
int next;
} pool[2 * N];
int nn, head[N];
void addEdge(int u, int v) {
pool[++nn] = {v, head[u]};
head[u] = nn;
}
int n, m, rt, MOD;
int a[N];
int fa[N], sz[N], son[N], top[N], dep[N];
// 维护 sz[u], son[u]
void dfs1(int u, int f) {
fa[u] = f;
sz[u] = 1;
dep[u] = dep[f] + 1;
for(int i = head[u]; i; i = pool[i].next) {
int v = pool[i].v;
if(v == f) continue;
dfs1(v, u);
sz[u] += sz[v];
if(son[u] == 0 || sz[v] > sz[son[u]]) {
son[u] = v;
}
}
}
int dfn[N], id[N], dt;
// 记录 dfs 序
void dfs2(int u, int f, int tp) {
dfn[u] = ++dt;
id[dt] = u;
top[u] = tp;
if(son[u]) dfs2(son[u], u, tp);
for(int i = head[u]; i; i = pool[i].next) {
int v = pool[i].v;
if(v == f) continue;
if(v == son[u]) continue;
dfs2(v, u, v);
}
}
namespace seg_tree {
int sum[4 * N], tag[4 * N];
inline int lc(int x) { return x << 1; }
inline int rc(int x) { return x << 1 | 1; }
void push_up(int p) {
sum[p] = (sum[lc(p)] + sum[rc(p)]) % MOD;
}
void move_tag(int p, int l, int r, int tg) {
sum[p] = (sum[p] + tg * (r - l + 1)) % MOD;
tag[p] = (tag[p] + tg) % MOD;
}
void push_down(int p, int l, int r) {
int mid = (l + r) >> 1;
move_tag(lc(p), l, mid, tag[p]);
move_tag(rc(p), mid + 1, r, tag[p]);
tag[p] = 0;
}
void build_tree(int p, int l, int r) {
if(l == r) {
move_tag(p, l, r, a[id[l]]);
return;
}
int mid = (l + r) >> 1;
build_tree(lc(p), l, mid);
build_tree(rc(p), mid + 1, r);
push_up(p);
}
void modify(int p, int l, int r, int ql, int qr, int val) {
if(ql <= l && r <= qr) {
move_tag(p, l, r, val);
return;
}
int mid = (l + r) >> 1;
push_down(p, l, r);
if(mid >= ql) modify(lc(p), l, mid, ql, qr, val);
if(mid < qr) modify(rc(p), mid + 1, r, ql, qr, val);
push_up(p);
}
int query(int p, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
return sum[p];
}
int mid = (l + r) >> 1, res = 0;
push_down(p, l, r);
if(mid >= ql) res += query(lc(p), l, mid, ql, qr);
if(mid < qr) res += query(rc(p), mid + 1, r, ql, qr);
return res % MOD;
}
}
void modify_path(int x, int y, int v) {
while(true) {
if(top[x] == top[y]) {
seg_tree::modify(1, 1, n, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), v);
break;
}
if(dep[top[x]] > dep[top[y]]) {
seg_tree::modify(1, 1, n, dfn[top[x]], dfn[x], v);
x = fa[top[x]];
} else {
seg_tree::modify(1, 1, n, dfn[top[y]], dfn[y], v);
y = fa[top[y]];
}
}
}
int query_path(int x, int y) {
int res = 0;
while(true) {
if(top[x] == top[y]) {
res += seg_tree::query(1, 1, n, min(dfn[x], dfn[y]), max(dfn[x], dfn[y]));
res %= MOD;
break;
}
if(dep[top[x]] > dep[top[y]]) {
res += seg_tree::query(1, 1, n, dfn[top[x]], dfn[x]);
res %= MOD;
x = fa[top[x]];
} else {
res += seg_tree::query(1, 1, n, dfn[top[y]], dfn[y]);
res %= MOD;
y = fa[top[y]];
}
}
return res;
}
void modify_tree(int x, int v) {
seg_tree::modify(1, 1, n, dfn[x], dfn[x] + sz[x] - 1, v);
}
int query_tree(int x) {
return seg_tree::query(1, 1, n, dfn[x], dfn[x] + sz[x] - 1);
}
signed main() {
cin >> n >> m >> rt >> 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;
addEdge(u, v);
addEdge(v, u);
}
dfs1(rt, 0);
dfs2(rt, 0, rt);
seg_tree::build_tree(1, 1, n);
while(m--) {
int op;
cin >> op;
if(op == 1) {
int x, y, v;
cin >> x >> y >> v;
modify_path(x, y, v);
} else if(op == 2) {
int x, y;
cin >> x >> y;
cout << query_path(x, y) << endl;
} else if(op == 3) {
int x, v;
cin >> x >> v;
modify_tree(x, v);
} else {
int x;
cin >> x;
cout << query_tree(x) << endl;
}
}
return 0;
}