#include <stdio.h>
#include <iostream>
#define maxn 100005
#define ll long long
using namespace std;
struct node {
int pre, to;
} g[maxn << 1];
struct Node {
ll l, r, val, ch;
} tree[maxn << 2];
ll n, m, root, p, cnt, dd;
ll v[maxn], f[maxn], rk[maxn], ii[maxn], val[maxn];
ll top[maxn], son[maxn], d[maxn], size[maxn];
void updown(int rt) {
if(tree[rt].ch) {
tree[rt].ch %= p;
tree[rt << 1].val += (tree[rt << 1].r - tree[rt << 1].l + 1) % p * tree[rt].ch;
tree[rt << 1].val %= p;
tree[rt << 1 | 1].val += (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) % p * tree[rt].ch;
tree[rt << 1 | 1].val %= p;
tree[rt << 1].ch = tree[rt << 1 | 1].ch = tree[rt].ch;
tree[rt].ch = 0;
}
}
void update(int rt) {
tree[rt].val = (tree[rt << 1].val + tree[rt << 1 | 1].val) % p;
return ;
}
void add(int fa, int child) {
g[++cnt].pre = v[fa];
g[cnt].to = child;
v[fa] = cnt;
}
void dfs1(int u, int deepth) {
d[u] = deepth;
size[u] = 1;
for(int i = v[u]; i; i = g[i].pre) {
int p = g[i].to;
if(p == f[u]) continue;
f[p] = u;
dfs1(p, deepth + 1);
if(size[son[u]] < size[p])
son[u] = p;
size[u] += size[p];
}
return ;
}
void dfs2(int u, int t) {
top[u] = t;
ii[u] = ++dd;
rk[dd] = u;
if(!son[u]) return ;
dfs2(son[u], t);
for(int i = v[u]; i; i = g[i].pre) {
int p = g[i].to;
if(p == f[u] || p == son[u])
continue;
dfs2(p, p);
}
return ;
}
void build(int rt) {
if(tree[rt].l == tree[rt].r) {
tree[rt].val = val[rk[tree[rt].l]];
return ;
}
ll mid = (tree[rt].l + tree[rt].r) >> 1;
tree[rt << 1].l = tree[rt].l;
tree[rt << 1].r = mid;
tree[rt << 1 | 1].l = mid + 1;
tree[rt << 1 | 1].r = tree[rt].r;
build(rt << 1);
build(rt << 1 | 1);
update(rt);
return ;
}
ll Que(int rt, int L, int R) {
if(tree[rt].l >= L && tree[rt].r <= R)
return tree[rt].val;
ll mid = (tree[rt].l + tree[rt].r) >> 1;
ll ans = 0;
updown(rt);
if(mid >= L) ans += Que(rt << 1, L, R);
ans %= p;
if(mid < R) ans += Que(rt << 1 | 1, L, R);
ans %= p;
return ans;
}
void Inadd(int rt, int L, int R, int k) {
if(tree[rt].l >= L && tree[rt].r <= R) {
tree[rt].ch = k;
tree[rt].val += (tree[rt].r - tree[rt].l + 1) % p * k % p;
tree[rt].val %= p;
updown(rt);
return ;
}
ll mid = (tree[rt].l + tree[rt].r) >> 1;
updown(rt);
if(mid >= L) Inadd(rt << 1, L, R, k);
if(mid < R) Inadd(rt << 1 | 1, L, R, k);
update(rt);
}
ll lca(int x, int y) {
ll fx = top[x], fy = top[y], ans = 0;
while(fx != fy) {
if(d[fx] >= d[fy]) {
ans += Que(1, ii[fx], ii[x]);
ans %= p;
x = f[fx], fx = top[x];
}
else {
ans += Que(1, ii[fy], ii[y]);
ans %= p;
y = f[fy], fy = top[y];
}
}
if(ii[x] <= ii[y])
ans += Que(1, ii[x], ii[y]);
else
ans += Que(1, ii[y], ii[x]);
ans %= p;
return ans;
}
void lcaadd(int x, int y, int k) {
int fx = top[x], fy = top[y];
while(fx != fy) {
if(d[fx] >= d[fy]) {
Inadd(1, ii[fx], ii[x], k);
x = f[fx], fx = top[x];
}
else {
Inadd(1, ii[fy], ii[y], k);
y = f[fy], fy = top[y];
}
}
if(ii[x] >= ii[y])
Inadd(1, ii[y], ii[x], k);
else
Inadd(1, ii[x], ii[y], k);
return ;
}
void sontreeadd(int u, int k) {
Inadd(1, ii[u], ii[u] + size[u] - 1, k);
}
int sontreeque(int u) {
return Que(1, ii[u], ii[u] + size[u] - 1);
}
int main() {
ll x, y, z, w;
scanf("%d%d%d%lld", &n, &m, &root, &p);
for(int i = 1; i <= n; ++i)
scanf("%lld", &val[i]);
for(int i = 1; i <= n - 1; ++i) {
scanf("%d%d", &x, &y);
add(x, y), add(y, x);
}
dfs1(root, 1);
dfs2(root, root);
tree[1].l = 1, tree[1].r = dd;
build(1);
for(int i = 1; i <= m; ++i) {
scanf("%d", &x);
if(x == 1) {
scanf("%d%d%d", &y, &z, &w);
w %= p;
lcaadd(y, z, w);
}
if(x == 2) {
scanf("%d%d", &y, &z);
printf("%lld\n", lca(y, z) % p);
}
if(x == 3) {
scanf("%d %d", &y, &z);
z %= p;
sontreeadd(y, z);
}
if(x == 4) {
scanf("%d", &y);
printf("%lld\n", sontreeque(y) % p);
}
}
}
/*
8 10 2 448348
458 718 447 857 633 264 238 944
1 2
2 3
3 4
6 2
1 5
5 7
8 6
3 7 611
4 6
3 1 267
3 2 111
1 6 3 153
3 7 673
4 8
2 6 1
4 7
3 4 228
1208
1055
2346
1900
*/
求哪位大佬帮忙找错QAQ