#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<iostream>
#include<cmath>
#include<random>
#define MAX_SIZE 1000007
#define HASH_SIZE 4000
#define INT_MIN -9999999
#define INT_MAX 99999999
#define HASHMOD 47
using namespace std;
int fa[MAX_SIZE];
int top[MAX_SIZE];
int son[MAX_SIZE];
int dfn[MAX_SIZE];
int seg[MAX_SIZE];
int size_[MAX_SIZE];
long long MOD;
int dfnnum = 0;
int weight[MAX_SIZE];
long long addL[MAX_SIZE<<1];
long long sum[MAX_SIZE<<1];
int deep[MAX_SIZE];
int head[MAX_SIZE];
int to[MAX_SIZE];
int next_[MAX_SIZE];
int cnt = 1;
void addedge(int u, int v) {
next_[cnt] = head[u];
to[cnt] = v;
head[u] = cnt++;
}
void build(int n) {
cnt = 1;
for (int i = 1;i <= n;i++) {
head[i] = 0;
}
}
void up(int i) {
sum[i] = (sum[i << 1] + sum[i << 1 | 1])%MOD;
}
void buildTree(int l,int r,int i) {
if (l == r) {
sum[i] = weight[seg[l]]%MOD;
}
else {
int mid = (l + r) >> 1;
buildTree(l, mid, i << 1);
buildTree(mid + 1, r, i << 1 | 1);
up(i);
}
}
void dfs1(int u, int f) {
fa[u] = f;
size_[u] = 1;
deep[u] = deep[f] + 1;
for (int e = head[u];e > 0;e = next_[e]) {
int v = to[e];
if (v != f) {
dfs1(v, u);
}
}
for (int e = head[u];e > 0;e = next_[e]) {
int v = to[e];
if (v != f) {
size_[u] += size_[v];
if (son[u] == 0 || size_[son[u]] < size_[v]) {
son[u] = v;
}
}
}
}
void dfs2(int u,int t) {
top[u] = t;
dfn[u] = ++dfnnum;
seg[dfnnum] = u;
if (son[u] == 0)return;
dfs2(son[u], t);
for (int e = head[u];e > 0;e = next_[e]) {
int v = to[e];
if (v != fa[u]) {
if (v != son[u]) {
dfs2(v, v);
}
}
}
}
void lazy(int n ,int i, int v) {
sum[i] = (sum[i]+v * n)%MOD;
addL[i] = (addL[i]+v)%MOD;
}
void down(int i, int ln, int rn) {
if (addL[i] != 0) {
lazy(ln,i<<1,addL[i]);
lazy(rn, i << 1 | 1, addL[i]);
addL[i] = 0;
}
}
void addT(int jobl, int jobr, int l, int r,int i, int v) {
if (jobl<=l&&jobr>=r) {
lazy(r-l+1, i, v);
}
else {
int mid = (l + r) >> 1;
down(i, mid - l+1, r - mid);
if (jobl<=mid) {
addT(jobl, jobr, l, mid, i << 1,v);
}
if(jobr>mid) {
addT(jobl, jobr, mid + 1, r, i << 1|1, v);
}
up(i);
}
}
void Addall(int x, int y, int z,int n) {
while (top[x]!=top[y]) {
if (deep[x] >= deep[y]) {
addT(dfn[top[x]], dfn[x], 1, n,1, z);
x = fa[top[x]];
}
else {
addT(dfn[top[y]], dfn[y], 1, n,1, z);
y = fa[top[y]];
}
}
int l = std::min(dfn[x], dfn[y]);
int r = std::max(dfn[x], dfn[y]);
addT(l, r, 1, n,1, z);
}
long long query(int jobl, int jobr, int l, int r, int i) {
if (jobl <= l && jobr >= r) {
return sum[i];
}
long long ans = 0;
int mid = (l + r) >> 1;
down(i, mid - l + 1, r - mid);
if (jobl<=mid) {
ans=(ans+query(jobl, jobr, l, mid, i << 1))%MOD;
}
if (jobr >mid) {
ans = (ans+query(jobl, jobr, mid + 1, r, i << 1 | 1))%MOD;
}
return ans;
}
long long queryall(int x, int y, int n) {
long long ans = 0;
while (top[x] != top[y]) {
if (deep[x] >= deep[y]) {
ans = (ans+query(dfn[top[x]],dfn[x],1,n,1))%MOD;
x = fa[top[x]];
}
else {
ans = (ans+query(dfn[top[y]],dfn[y],1,n,1))%MOD;
y = fa[top[y]];
}
}
ans = (ans+query(min(dfn[x], dfn[y]), max(dfn[x], dfn[y]), 1, n, 1))%MOD;
return ans;
}
int main() {
int N, M, R;
long long P;
cin >> N;
cin >> M;
cin >> R;
cin >> P;
build(N);
for (int i = 1;i <= N;i++) {
scanf("%d", &weight[i]);
}
for (int i = 0;i < N-1;i++) {
int u, v;
cin >> u >> v;
addedge(u, v);
addedge(v, u);
}
MOD = P;
dfs1(R,0);
dfs2(R,R);
buildTree(1,N,1);
for (int i = 0;i < M;i++) {
int op;
cin >> op;
if (op == 1) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
Addall(x, y, z,N);
}
else if (op == 2) {
int x, y;
cin >> x >> y;
long long ans = 0;
ans=queryall(x, y, N);
printf("%lld\n", ans);
}
else if (op == 3) {
int x, y;
scanf("%d%d", &x, &y);
int jobl = dfn[x];
int jobr = size_[x] + dfn[x]-1;
addT(jobl,jobr,1,N,1,y);
}
else if (op == 4) {
int x;
cin >> x;
long long ans = 0;
int jobl = dfn[x];
int jobr = size_[x] + dfn[x] - 1;
printf("%lld\n", query(jobl, jobr, 1, N, 1));
}
}
return 0;
}