0pts......
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INPUT_OPTIMIZE
#define OUTPUT_OPTIMIZE
namespace IO {
#ifdef INPUT_OPTIMIZE
static char buf[1 << 21], *p1 = buf, *p2 = buf;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
#endif
template
<typename T>
inline
bool read(T &t) {
t = 0;
char c = getchar(); bool f = 1;
while (isspace(c)) c = getchar();
if (c == '-') f = 0, c = getchar();
while (isdigit(c)) t = (t << 3) + (t << 1) + (c ^ 48), c = getchar();
t *= f ? 1 : -1;
return c == EOF;
}
template
<typename T, typename... Args>
inline
bool read(T &t, Args&... args) {
return read(t) ? 1 : read(args...);
}
#ifdef INPUT_OPTIMIZE
#undef getchar()
#endif
#ifdef OUTPUT_OPTIMIZE
static char outbuf[1 << 24], *out = outbuf;
#define putchar(x) *out++ = x
#define flush() fwrite(outbuf, 1, out - outbuf, stdout), out = outbuf
#endif
template
<typename T>
inline
void recwrite(T x) {
if (x >= 10) recwrite(x / 10);
putchar(x % 10 + '0');
}
template
<typename T>
inline
void write(T x) {
if (x < 0) putchar('-'), x = -x;
recwrite(x);
}
}
using namespace IO;
const int MAXN = 1e5 + 10;
int N, M, R, P;
struct edge {
int v, nxt;
} e[MAXN << 1];
int tot, head[MAXN], w[MAXN], wt[MAXN];
inline
void add(int u, int v) {
e[++tot] = { v, head[u] }, head[u] = tot;
}
struct sgtree {
int l, r;
int sum, add;
} t[MAXN << 2];
inline
int update(int p) {
t[p].sum = (t[p << 1].sum + t[p << 1 | 1].sum) % P;
}
inline
int calc(int p) {
return t[p].r - t[p].l + 1;
}
inline
void pushdown(int p) {
if (!t[p].add) return ;
int len = t[p].r - t[p].l + 1;
t[p << 1].add += t[p].add, t[p << 1 | 1].add += t[p].add;
t[p << 1].sum = (t[p << 1].sum + t[p].add * calc(p << 1)) % P;
t[p << 1 | 1].sum = (t[p << 1 | 1].sum + t[p].add * calc(p << 1 | 1)) % P;
t[p].add = 0;
}
void build(int l, int r, int p) {
t[p].l = l, t[p].r = r;
if (l == r) {
t[p].sum = wt[l] % P;
return ;
}
int mid = l + r >> 1;
build(l, mid, p << 1), build(mid + 1, r, p << 1 | 1);
update(p);
}
int query(int l, int r, int p) {
if (l <= t[p].l && t[p].r <= r) return t[p].sum;
pushdown(p);
int mid = t[p].l + t[p].r >> 1, ans = 0;
if (l <= mid) ans = (ans + query(l, mid, p << 1)) % P;
if (r > mid) ans = (ans + query(mid + 1, r, p << 1 | 1)) % P;
return ans;
}
void update(int l, int r, int p, int k) {
if (l <= t[p].l && t[p].r <= r) return (void)(t[p].add += k, t[p].sum += k * calc(p));
pushdown(p);
int mid = t[p].l + t[p].r >> 1;
if (l <= mid) update(l, mid, p << 1, k);
if (r > mid) update(mid + 1, r, p << 1 | 1, k);
update(p);
}
int cnt, son[MAXN], dep[MAXN], fa[MAXN], size[MAXN], top[MAXN], id[MAXN];
void dfs1(int f, int u) {
fa[u] = f, dep[u] = dep[f] + 1, size[u] = 1;
int mson = -1;
for (int i = head[u]; i; i = e[i].nxt) {
if (e[i].v == f) continue;
dfs1(u, e[i].v);
size[u] += size[e[i].v];
if (size[e[i].v] > mson) son[u] = e[i].v, mson = size[e[i].v];
}
}
void dfs2(int u, int ftop) {
id[u] = ++cnt, wt[cnt] = w[u], top[u] = ftop;
if (!son[u]) return ;
dfs2(son[u], ftop);
for (int i = head[u]; i; i = e[i].nxt) {
if (e[i].v != fa[u] && e[i].v != son[u]) dfs2(e[i].v, e[i].v);
}
}
inline
int qrange(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(id[top[x]], id[x], 1)) % P;
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x,y);
ans = (ans + query(id[x], id[y], 1)) % P;
return ans;
}
inline
void updrange(int x, int y, int k) {
k %= P;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(id[top[x]], id[x], 1, k);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x,y);
update(id[x], id[y], 1, k);
}
inline
int qson(int x) {
return query(id[x], id[x] + size[x] - 1, 1);
}
inline
void updson(int x, int k) {
update(id[x], id[x] + size[x] - 1, 1, k);
}
int k, x, y, z;
int main() {
read(N, M, R, P);
for (int i = 1; i <= N; i++) read(w[i]);
for (int i = 1; i < N; i++) {
read(x, y), add(x, y), add(y, x);
}
dfs1(0, R), dfs2(R, R);
build(1, N, 1);
//for (int i = 1; i <= N; i++) write(top[i]), putchar(' '); putchar('\n');
while (M--) {
//for (int i = 1; i < N << 1; i++) pushdown(i), write(t[i].sum), putchar(' '); putchar('\n');
read(k);
switch (k) {
case 1: read(x, y, z), updrange(x, y, x); break;
case 2: read(x, y), write(qrange(x, y)), putchar('\n'); break;
case 3: read(x, z), updson(x, z); break;
case 4: read(x), write(qson(x)), putchar('\n'); break;
}
}
return flush(), 0;
}