#2#9#10莫名TLE
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 2e6 + 5;
int n, m, s;
int num;
int cnt, mod;
int a[N], b[N], fa[N];//b是原数据, a是dfs序数据
int idx[N], top[N];//idx是x的dfs序
int son[N], tot[N];//重儿子, 重量
int deep[N], head[N];
struct bal {
int nxt;
int to;
};
bal e[N<<1];
struct ball {
int l, r;
int sum;
int size;
int lazy;
};
ball t[N<<2];
int re() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0'||ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
}
while (ch <= '9'&&ch >= '0') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void add(int u, int v) {
++cnt;
e[cnt].nxt = head[u];
e[cnt].to = v;
head[u] = cnt;
}
int dfs1(int x, int f, int dep) {//预处理
deep[x] = dep;
tot[x] = 1; fa[x] = f;
int maxson = -1;
for(int i = head[x]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == f) continue;
tot[x] += dfs1(v, x, dep + 1);//回溯求重量
maxson = max(maxson, tot[v]);//维护x的重儿子
}
son[x] = maxson;
return tot[x];
}
void dfs2(int x, int ftop) {//找top
idx[x] = ++num;
a[num] = b[x];
top[x] = ftop;
if(!son[x]) return;//到底了就返回
for(int i = head[x]; i; i = e[i].nxt) {
int v = e[i].to;
if(!idx[v]) dfs2(v, v);
}
}
void update(int k) {
t[k].sum = (t[k<<1].sum + t[k<<1|1].sum + mod) % mod;
}
void pushdown(int k) {
if(!t[k].lazy) return ;
t[k<<1].sum += (t[k<<1].size * t[k].lazy + mod) % mod;
t[k<<1|1].sum += (t[k<<1|1].size * t[k].lazy + mod) % mod;
t[k<<1].lazy += t[k].lazy;
t[k<<1|1].lazy += t[k].lazy;
t[k].lazy = 0;
}
void build(int p, int l, int r) {
if(l < 0||r > n) return ;
t[p].l = l; t[p].r = r;
t[p].size = (r - l) + 1;
if(l == r) {
t[p].sum = a[l];
return ;
}
int mid = (l + r) / 2;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
update(p);
}
void Interval_addition(int p, int l, int r, int val) {//路径加
if(l <= t[p].l&&r >= t[p].r) {
t[p].sum += (t[p].size * val + mod) % mod;
t[p].lazy += val;
return ;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
if(l <= mid) Interval_addition(p<<1, l, r, val);
if(r > mid) Interval_addition(p<<1|1, l, r, val);
update(p);
}
int Interval_summation(int p, int l, int r) {//路径求和
if(t[p].l >= l&&t[p].r <= r) {
return t[p].sum;
}
int mid = (t[p].l + t[p].r)>>1;
pushdown(p); int ans = 0;
if(l <= mid) ans = (ans + Interval_summation(p<<1, l, r) + mod) % mod;
if(r > mid) ans = (ans + Interval_summation(p<<1|1, l, r) + mod) % mod;
return ans;
}
void Tree_addition(int x, int y, int val) {//子树加
while (top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
Interval_addition(1, idx[top[x]], idx[x], val);
x = fa[top[x]];
}
if(deep[x] < deep[y]) swap(x ,y);
Interval_addition(1, idx[y], idx[x], val);
}
void Tree_summation(int x, int y) {//子树求和
int ans = 0;
while (top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
ans = (ans + Interval_summation(1, idx[top[x]], idx[x])) % mod;
x = fa[top[x]];
}
if(deep[x] < deep[y]) swap(x, y);
ans = (ans + Interval_summation(1, idx[y], idx[x])) % mod;
printf("%d\n", ans);
}
int main() {
int xi, yi, op;
int x, y, z;
n = re(); m = re();
s = re(); mod = re();
for(int i = 1; i <= n; i++)
b[i] = re();
for(int i = 1; i < n; i++) {
xi = re(); yi = re();
add(xi, yi); add(yi, xi);
}
dfs1(s, 0, 1);
dfs2(s, s);
build(1, 1, n);
while (m--) {
op = re();
if(op == 1) {
x = re(); y = re(); z = re();
Tree_addition(x, y, z);
}
else if(op == 2) {
x = re(); y = re();
Tree_summation(x, y);
}
else if(op == 3) {
x = re(); z = re();
Interval_addition(1, idx[x], idx[x] + tot[x] - 1, z % mod);
}
else if(op == 4) {
x = re();
cout << Interval_summation(1, idx[x], idx[x] + tot[x] - 1) << endl;
}
}
return 0;
}