#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#define rep(i, l, r) for(int i = (l); i <= (r); ++i)
#define endl '\n'
#define lson(x) x << 1
#define rson(x) x << 1 | 1
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
struct Edge {
int v, nxt;
}e[N << 1];
struct Tree {
int l, r;
ll sum, laz;
}t[N << 2];
int n, m, rt, P;
int ec, head[N];
int siz[N], son[N], fst[N], depth[N], id[N], cnt, pre[N];
ll w1[N], w[N];
inline void add_e(int u, int v) {
e[++ec].v = v;
e[ec].nxt = head[u];
head[u] = ec;
}
void init(int cur, int fath) {
depth[cur] = depth[fath] + 1;
siz[cur] = 1;
for (int i = head[cur]; i; i = e[i].nxt) {
int v = e[i].v;
if (v == fath) continue;
init(v, cur);
siz[cur] += siz[v];
if (siz[v] > siz[son[cur]])
son[cur] = v;
}
}
void number(int cur, int fath, int f) {
pre[cur] = fath;
id[cur] = ++cnt;
w[cnt] = w1[cur];
fst[cur] = f;
if (son[cur]) number(son[cur], cur, f);
for (int i = head[cur]; i; i = e[i].nxt) {
int v = e[i].v;
if (v == fath || v == son[cur]) continue;
number(v, cur, v);
}
}
inline void pushup(int x) { t[x].sum = (t[lson(x)].sum + t[rson(x)].sum) % P; }
inline void pushdown(int x) {
ll tmp = t[x].laz; t[x].laz = 0;
t[lson(x)].laz = (t[lson(x)].laz + tmp) % P;
t[lson(x)].sum += tmp * (ll)(t[lson(x)].r - t[lson(x)].l + 1) % P;
t[lson(x)].sum %= P;
t[rson(x)].laz = (t[rson(x)].laz + tmp) % P;
t[rson(x)].sum += tmp * (ll)(t[rson(x)].r - t[rson(x)].l + 1) % P;
t[rson(x)].sum %= P;
}
void build(int cur, int l, int r) {
t[cur].l = l; t[cur].r = r; t[cur].laz = 0;
if (l == r) { t[cur].sum = w[l]; return; }
t[cur].sum = 0;
int mid = (l + r) >> 1;
build(lson(cur), l, mid);
build(rson(cur), mid + 1, r);
pushup(cur);
}
inline bool is_intersect(int x, int L, int R) {
return !(t[x].r < L || t[x].l > R);
}
void add(int cur, int L, int R, int val) {
int l = t[cur].l, r = t[cur].r;
if (L <= l && r <= R) {
t[cur].sum = (t[cur].sum + val) % P;
t[cur].laz = (t[cur].laz + val) % P;
return;
}
pushdown(cur);
if (is_intersect(lson(cur), L, R)) add(lson(cur), L, R, val);
if (is_intersect(rson(cur), L, R)) add(rson(cur), L, R, val);
pushup(cur);
}
ll query(int cur, int L, int R) {
int l = t[cur].l, r = t[cur].r;
if (L <= l && r <= R)
return t[cur].sum;
pushdown(cur);
ll ans = 0;
if (is_intersect(lson(cur), L, R)) {
ans += query(lson(cur), L, R); ans %= P;
}
if (is_intersect(rson(cur), L, R)) {
ans += query(rson(cur), L, R); ans %= P;
}
return ans;
}
void add_route(int a, int b, ll val) {
while (fst[a] != fst[b]) {
if (depth[fst[a]] < depth[fst[b]]) swap(a, b);
add(1, id[fst[a]], id[a], val);
a = pre[fst[a]];
}
if (id[a] > id[b]) swap(a, b);
add(1, id[a], id[b], val);
}
ll query_route(int a, int b) {
ll ans = 0;
while (fst[a] != fst[b]) {
if (depth[fst[a]] < depth[fst[b]]) swap(a, b);
ans += query(1, id[fst[a]], id[a]);
ans %= P;
a = pre[fst[a]];
}
if (id[a] > id[b]) swap(a, b);
ans += query(1, id[a], id[b]);
ans %= P;
return ans;
}
void add_t(int root, int val) {
add(1, id[root], id[root] + siz[root] - 1, val);
}
ll query_t(int root) {
return query(1, id[root], id[root] + siz[root] - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m >> rt >> P;
rep(i, 1, n) cin >> w1[i];
rep(i, 1, n - 1) {
int x, y;
cin >> x >> y;
add_e(x, y); add_e(y, x);
}
init(rt, 0);
number(rt, 0, rt);
build(1, 1, cnt);
rep(i, 1, m) {
int opt; cin >> opt;
switch (opt) {
int x, y; ll val;
case 1:
cin >> x >> y >> val;
add_route(x, y, val);
break;
case 2:
cin >> x >> y;
cout << query_route(x, y) << endl;
break;
case 3:
cin >> x >> val;
add_t(x, val);
break;
case 4:
cin >> x;
cout << query_t(x) << endl;
break;
}
}
return 0;
}