#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<map>
#include<utility>
#include<queue>
#include<set>
#include<vector>
#include<unordered_set>;
using namespace std;
typedef long long ll;
#define endl '\n';
struct node
{
ll u, v, next;
}edge[5000005];
ll cnt = 0;
ll head[5000005];
void add(ll u, ll v)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
ll a[5000005];
ll fa[5000005];
ll top[5005005];
ll num[5005005];
ll son[5005005];
ll dep[5000505];
#define _for(i,a) for(ll i=1;i<=a;i++);
ll n, m, r, mod;
void dfs1(ll u, ll f)
{
fa[u] = f;
num[u] = 1;
dep[u] = dep[f] + 1;
for (int i = head[u]; i + 1; i = edge[i].next)
{
ll v = edge[i].v;
if (v == f)continue;
dfs1(v, u);
num[u] += num[v];
if (num[son[u]] < num[v])
{
son[u] = v;
}
}
}
ll id[5000005];
ll newnum[5000005];
ll tot = 0;
void dfs2(ll u, ll to)
{
top[u] = to;
id[u] = ++tot;
newnum[id[u]] = a[u];
if (!son[u])return;
dfs2(son[u], to);
for (int i = head[u]; i + 1; i = edge[i].next)
{
ll v = edge[i].v;
if (v == fa[u] || v == son[u])continue;
dfs2(v, v);
}
}
struct node11
{
ll l, r, lazy, sum;
}t[5000005];
void push_down(ll p)
{
if (t[p].lazy)
{
ll xx = t[p].lazy;
t[p].lazy = 0;
t[p * 2].lazy =(t[p*2].lazy+ xx)%mod;
t[p * 2 + 1].lazy =(t[p*2+1].lazy+ xx)%mod;
t[p * 2 + 1].sum =(t[p*2+1].sum+ (((t[p * 2 + 1].r - t[p * 2 + 1].l + 1))%mod)*xx)%mod;
t[p * 2].sum =(t[p*2].sum+ (((t[p * 2].r - t[p * 2].l + 1))%mod)*xx)%mod;
}
}
void push_up(ll p)
{
t[p].sum = (t[p * 2].sum + t[p * 2 + 1].sum)%mod;
}
ll query(ll p, ll l, ll r)
{
if (t[p].l >= l && t[p].r <= r)
{
return t[p].sum%mod;
}
push_down(p);
ll res = 0;
ll mid =( t[p].l+t[p].r)/2;
if (mid >= l)res = (res+query(p * 2, l,r))%mod;
if (mid<r)res = (res+query(p * 2 + 1, l, r))%mod;
return res;
}
void build(ll p, ll l, ll r)
{
t[p].l = l;
t[p].r = r;
if (l == r)
{
t[p].sum = newnum[l];
return;
}
ll mid = (l + r) / 2;
if (mid >= l)
{
build(p * 2, l, mid);
}
if (mid < r)
{
build(p * 2 + 1, mid + 1, r);
}
push_up(p);
}
void update(ll p, ll l, ll r,ll x)
{
if (t[p].l >= l && t[p].r <= r)
{
t[p].sum =(t[p].sum+ ((t[p].r - t[p].l + 1)*x)%mod)%mod;
t[p].lazy =(t[p].lazy +x)%mod;
return;
}
push_down(p);
ll mid = (t[p].l + t[p].r) / 2;
if (mid >= l)
update(p * 2, l, r,x);
if (mid < r)
update(p * 2 + 1, l, r, x);
push_up(p);
}
void update_path(ll p,ll u,ll v,ll x)
{
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])swap(u, v);
update(1, id[top[u]], id[u], x);
u = fa[top[u]];
}
if (dep[u] < top[v])swap(u, v);
update(1, id[v], id[u], x);
}
ll query_path(ll p, ll u, ll v)
{
ll res = 0;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])swap(u, v);
res = (res+query(1, id[top[u]], id[u]))%mod;
u = fa[top[u]];
}
if (dep[u] < dep[v])swap(u, v);
res = (res+query(1, id[v], id[u]))%mod;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(head, -1, sizeof(head));
cin >> n >> m >> r >> mod;
for (int i = 1; i <= n; i++) { cin >> a[i]; a[i] %= mod; }
for (int i = 1; i < n; i++)
{
ll u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
dfs1(r,r);
dfs2(r,r);
build(1, 1, n);
while (m--)
{
ll op;
cin >> op;
if (op == 1)
{
ll x, y, z;
cin >> x >> y >> z;
update_path(1, x, y, z);
}
else if(op==2)
{
ll x, y;
cin >> x >> y;
cout<<(query_path(1, x, y))%mod<<endl;
}
else if (op == 3)
{
ll x, y;
cin >> x >> y;
update(1,id[x], id[x] + num[x] - 1, y);
}
else if (op == 4)
{
ll x;
cin >> x;
cout << (query(1,id[x], id[x] + num[x] - 1))%mod<<endl;
}
}
}