#include<stdio.h>
#define N 200009
#define ls (p << 1)
#define rs ((p << 1) + 1)
#define int long long
int a[N], head[N], cnt, mod, n, tot;
struct node
{
int v, nxt;
}e[N << 1];
int fa[N], deep[N], siz[N], hson[N], top[N], dfn[N], b[N];
void dfs1(int u, int fath)
{
siz[u] = 1;
hson[u] = -1;
deep[u] = deep[fath] + 1;
fa[u] = fath;
for (int i = head[u];i;i = e[i].nxt)
if (fath != e[i].v)
{
dfs1(e[i].v, u), siz[u] += siz[e[i].v];
if (hson[u] == -1 || siz[e[i].v] > siz[hson[u]])
hson[u] = e[i].v;
}
}
inline void add(int u, int v)
{
e[++ cnt].v = v, e[cnt].nxt = head[u];
head[u] = cnt;
}
void dfs2(int u, int fath)
{
top[u] = fath;
dfn[u] = ++ tot;
a[tot] = b[u];
if (hson[u] == -1)
return;
dfs2(hson[u], fath);
for (int i = head[u];i;i = e[i].nxt)
if (!dfn[e[i].v])
dfs2(e[i].v, e[i].v);
}
int tree[N << 2], lazy[N << 2];
inline void pushdown(int l, int r, int p)
{
int mid = (l + r) >> 1;
tree[ls] = (tree[ls] + (lazy[ls] = (lazy[p] + lazy[ls]) % mod) * (mid - l + 1)) % mod;
tree[rs] = (tree[rs] + (lazy[rs] = (lazy[p] + lazy[rs]) % mod) * (r - mid)) % mod;
lazy[p] = 0;
}
void build(int l, int r, int p)
{
if (l == r)
{
tree[p] = a[l] % mod;
return;
}
int mid = (l + r) >> 1;
build(l, mid, ls);
build(mid + 1, r, rs);
tree[p] = (tree[ls] + tree[rs]) % mod;
}
void updata(int sl, int sr, int l, int r, int p, int k)
{
if (l >= sl && r <= sr)
{
lazy[p] = (lazy[p] + k) % mod;
tree[p] = (tree[p] + k * (r - l + 1)) % mod;
return;
}
if (lazy[p])
pushdown(l, r, p);
int mid = (l + r) >> 1;
if (sl <= mid)
updata(sl, sr, l, mid, ls, k);
if (sr > mid)
updata(sl, sr, mid + 1, r, rs, k);
tree[p] = (tree[ls] + tree[rs]) % mod;
}
int query(int sl, int sr, int l, int r, int p)
{
if (l >= sl && r <= sr)
return tree[p];
if(lazy[p])
pushdown(l, r, p);
int mid = (l + r) >> 1, ret = 0;
if (sl <= mid)
ret = query(sl, sr, l, mid, ls);
if (sr > mid)
ret += query(sl, sr, mid + 1, r, rs);
return ret % mod;
}
inline void swap(int& a, int& b) {int c = a;a = b, b = c;}
inline void change(int u, int v, int x)
{
x %= mod;
while (top[u] != top[v])
{
if (deep[top[u]] < deep[top[v]])
swap(u, v);
updata(dfn[top[u]], dfn[u], 1, n, 1, x);
u = fa[top[u]];
}
if (dfn[u] > dfn[v])
swap(u, v);
updata(dfn[u], dfn[v], 1, n, 1, x);
}
inline void ask(int u, int v)
{
int ans = 0;
while (top[u] != top[v])
{
if (deep[top[u]] < deep[top[v]])
swap(u, v);
ans = (query(dfn[top[u]], dfn[u], 1, n, 1) + ans) % mod;
u = fa[top[u]];
}
if (dfn[u] > dfn[v])
swap(u, v);
printf("%lld\n", (query(dfn[u], dfn[v], 1, n, 1) + ans) % mod);
}
inline void change1(int u, int x)
{
updata(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1, x % mod);
}
inline void ask1(int u)
{
printf("%lld\n", query(dfn[u], dfn[u] + siz[u] - 1, 1, n, 1));
}
signed main()
{
int m, r;
scanf("%lld%lld%lld%lld", &n, &m, &r, &mod);
for (int i = 1;i <= n;i ++)
scanf("%lld", &b[i]), b[i] %= mod;
int u, v;
for (int i = 1;i < n;i ++)
scanf("%lld%lld", &u, &v), add(u, v), add(v, u);
dfs1(r, 0);
dfs2(r, r);
build(1, n, 1);
int opt, x;
while (m --)
{
scanf("%lld%lld", &opt, &u);
if (opt == 1)
scanf("%lld%lld", &v, &x), change(u, v, x);
if (opt == 2)
scanf("%lld", &v), ask(u, v);
if (opt == 3)
scanf("%lld", &x), change1(u, x);
if (opt == 4)
ask1(u);
}
return 0;
}