#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
using namespace std;
const int N = 2e5 + 10;
int n, m, mod;
int fa[N], depth[N], size[N], son[N], top[N], dfn[N], w[N], cnt;
int v[N], root;
int h[N], to[N], ne[N], tot;
struct SGtree
{
int tree[N << 2], tag[N << 2];
void pushup(int x)
{
tree[x] = tree[ls(x)] + tree[rs(x)] % mod;
}
void build(int p, int l, int r)
{
if(l == r)
{
tree[p] = w[l] % mod;
return;
}
int mid = (l + r) >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
pushup(p);
}
void pushdown(int x, int l, int r)
{
if(tag[x])
{
int mid = (l + r) >> 1;
tree[ls(x)] += (mid - l + 1) * tag[x] % mod;
tree[ls(x)] %= mod;
tree[rs(x)] += (r - mid) * tag[x] % mod;
tree[rs(x)] %= mod;
tag[ls(x)] += tag[x];
tag[rs(x)] += tag[x];
tag[x] = 0;
}
}
int query(int p, int l, int r, int A, int B)
{
int ans = 0;
if(A <= l && r <= B)
{
return tree[p] % mod;
}
if(l > B && r < A)
{
return 0;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
ans += query(ls(p), l, mid, A, B) % mod + query(rs(p), mid + 1, r, A, B) % mod;
return ans % p;
}
void change(int p, int l, int r, int A, int B, int c)
{
if(A <= l && r <= B)
{
tree[p] += ((r - l + 1) * c) % mod;
tag[p] += c;
return;
}
if(l > B && r < A)
{
return;
}
pushdown(p, l, r);
int mid = (l + r) >> 1;
change(ls(p), l, mid, A, B, c);
change(rs(p), mid + 1, r, A, B, c);
pushup(p);
}
}a;
void change_son(int x, int c)
{
a.change(1, 1, n, dfn[x], dfn[x] + size[x] - 1, c);
}
int query_son(int x)
{
return a.query(1 ,1, n, dfn[x], dfn[x] + size[x] - 1);
}
void change_chain(int x, int y, int z)
{
z %= mod;
while(depth[top[x]] != depth[top[y]])
{
if(depth[top[x]] < depth[top[y]])
{
swap(x, y);
}
a.change(1, 1, n, dfn[top[x]], dfn[x], z);
x = fa[top[x]];
}
if(depth[x] > depth[y])
{
swap(x, y);
}
a.change(1, 1, n, dfn[x], dfn[y], z);
}
int query_chain(int x, int y)
{
int res = 0;
while(top[x] != top[y])
{
if(depth[top[x]] < depth[top[y]])
{
swap(x, y);
}
res += a.query(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(depth[x] > depth[y])
{
swap(x, y);
}
res += a.query(1, 1, n, dfn[x], dfn[y]);
return res % mod;
}
void add(int x, int y)
{
to[++cnt] = y;
ne[cnt] = h[x];
h[x] = cnt;
}
void dfs1(int u, int f)
{
size[u] = 1;
fa[u] = f;
depth[u] = depth[fa[u]] + 1;
int max_son = -1;
for(int i = h[u]; i; i = ne[i])
{
if(to[i] == fa[u])
{
continue;
}
int j = to[i];
dfs1(j, u);
size[u] += size[j];
if(size[j] > max_son)
{
max_son = size[j];
son[u] = j;
}
}
}
void dfs2(int u, int tp)
{
dfn[u] = ++tot;
top[u] = tp;
w[tot] = v[u];
if(!son[u])
{
return;
}
dfs2(son[u], tp);
for(int i = h[u]; i; i = ne[i])
{
if(to[i] == fa[u] || to[i] == son[u])
{
continue;
}
int j = to[i];
dfs2(j, j);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m >> root >> mod;
for(int i = 1;i <= n;i++)
{
cin >> v[i];
}
int x12, y12;
for(int i = 1;i < n;i++)
{
cin >> x12 >> y12;
add(x12, y12);
add(y12, x12);
}
dfs1(root, root);
dfs2(root, root);
a.build(1, 1, n);
int op = 0;
int x, y, z;
for(int i = 1;i <= m;i++)
{
cin >> op;
if(op == 1)
{
cin >> x >> y >> z;
change_chain(x, y, z);
}
else if(op == 2)
{
cin >> x >> y;
cout << query_chain(x, y) << endl;
}
else if(op == 3)
{
cin >> x >> z;
change_son(x, z);
}
else
{
cin >> x;
cout << query_son(x) << endl;
}
}
return 0;
}
ce + wa 谢谢!