#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
#define endl '\n'
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
const LL INFF = 0x3f3f3f3f3f3f3f3f;
#define debug(x) cout<< "[debug]" #x << " = " << x <<endl
int n, m, root, mod, cnt;
int a[N], nw[N], son[N];
int fa[N], sz[N], top[N];
int id[N], dep[N];
vector<int> ve[N];
struct node{
LL l, r;
LL sum, tag;
}v[N * 4];
void dfs1(int x, int f){
sz[x] = 1, fa[x] = f;
for(auto k : ve[x]){
if(k == f)continue;
dep[k] = dep[x] + 1;
dfs1(k, x);
sz[x] += sz[k];
if(sz[k] > sz[son[x]])son[x] = k;
}
}
void dfs2(int x, int t){
top[x] = t, id[x] = ++cnt, nw[cnt] = a[x];
if(!son[x])return ;
dfs2(son[x], t);
for(auto k : ve[x]){
if(k == fa[x] || k == son[x])continue;
dfs2(k, k);
}
}
void pushup(int u){
v[u].sum = v[u * 2].sum + v[u * 2 + 1].sum;
v[u].sum %= mod;
}
void build(int u, int l, int r){
if(l == r)v[u] = {l, r, nw[l] % mod};
else{
v[u] = {l, r};
int mid = (l + r) >> 1;
build(u * 2, l, mid);
build(u * 2 + 1, mid + 1, r);
pushup(u);
}
}
void settag(int u, LL k){
v[u].sum += (v[u].r - v[u].l + 1) * k;
v[u].sum %= mod;
v[u].tag += k;
}
void pushdown(int u){
if(v[u].tag){
settag(u * 2, v[u].tag);
settag(u * 2 + 1, v[u].tag);
v[u].tag = 0;
}
}
void update(int u, int l, int r, int k){
if(v[u].l == l && v[u].r == r){
settag(u, k);
}
else{
pushdown(u);
int mid = (v[u].l + v[u].r) >> 1;
if(r <= mid)update(u * 2, l, r, k);
else if(l > mid)update(u * 2 + 1, l, r, k);
else update(u * 2, l, mid, k), update(u * 2 + 1, mid + 1, r, k);
pushup(u);
}
}
LL query(int u, int l, int r){
if(v[u].l == l && v[u].r == r){
return v[u].sum;
}
else{
pushdown(u);
int mid = (v[u].l + v[u].r) >> 1;
if(mid >= r)return query(u * 2, l, r);
else if(l > mid)return query(u * 2 + 1, l, r);
else return query(u * 2, l, mid) + query(u * 2 + 1, mid + 1, r);
}
}
int query_path(int u, int v){
int res = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]])swap(u, v);
res += query(1, id[top[u]], id[u]);
res %= mod;
u = fa[top[u]];
};
if(dep[u] > dep[v])swap(u, v);
res += query(1, id[u], id[v]);
res %= mod;
return res;
}
void update_path(int u, int v, int k){
int cnt = 0;
while(top[u] != top[v]){
cnt++;
if(dep[top[u]] < dep[top[v]])swap(u, v);
update(1, id[top[u]], id[u], k);
u = fa[top[u]];
if(cnt == 1)break;
};
if(dep[u] > dep[v])swap(u, v);
update(1, id[u], id[v], k);
}
void solve()
{
cin >> n >> m >> root >> mod;
for(int i = 1; i <= n; i++)cin >> a[i];
for(int i = 1; i < n; i++){
int a, b;
cin >> a >> b;
ve[a].push_back(b);
ve[b].push_back(a);
}
dfs1(root, -1);
dfs2(root, root);
build(1, 1, n);
while(m--){
int q;
cin >> q;
if(q == 1){
int x, y, z;
cin >> x >> y >> z;
update_path(x, y, z);
}
else if(q == 2){
int x, y;
cin >> x >> y;
cout << query_path(x, y) % mod << endl;
}
else if(q == 3){
int x, z;
cin >> x >> z;
update(1, id[x], id[x] + sz[x] - 1, z);
}
else {
int x;
cin >> x;
cout << query(1, id[x], id[x] + sz[x] - 1) % mod << endl;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
while(T--)
{
solve();
}
}