1 #pragma comment(linker, "/STACK:1024000000,1024000000")
2 #include <cstdio>
3 #include <cstring>
4 #include <cstdlib>
5 #include <cmath>
6 #include <ctime>
7 #include <cctype>
8 #include <climits>
9 #include <iostream>
10 #include <iomanip>
11 #include <algorithm>
12 #include <string>
13 #include <sstream>
14 #include <stack>
15 #include <queue>
16 #include <set>
17 #include <map>
18 #include <vector>
19 #include <list>
20 #include <fstream>
21 #define ri readint()
22 #define gc getchar()
23 #define R(x) scanf("%d", &x)
24 #define W(x) printf("%d
", x)
25 #define init(a, b) memset(a, b, sizeof(a))
26 #define rep(i, a, b) for (int i = a; i <= b; i++)
27 #define irep(i, a, b) for (int i = a; i >= b; i--)
28 #define ls p << 1
29 #define rs p << 1 | 1
30 using namespace std;
31
32 typedef double db;
33 typedef long long ll;
34 typedef unsigned long long ull;
35 typedef pair<int, int> P;
36 const int inf = 0x3f3f3f3f;
37 const ll INF = 1e18;
38
39 inline int readint() {
40 int x = 0, s = 1, c = gc;
41 while (c <= 32) c = gc;
42 if (c == '-') s = -1, c = gc;
43 for (; isdigit(c); c = gc)
44 x = x * 10 + c - 48;
45 return x * s;
46 }
47
48 const int maxn = 1e5 + 5;
49 int n, m, root, mod, a[maxn];
50 int deep[maxn], fa[maxn], size[maxn], son[maxn], top[maxn], id[maxn], rnk[maxn], cnt;
51
52 struct Edge {
53 int to, nxt;
54 }e[maxn << 1];
55 int tot, head[maxn];
56
57 struct Seg {
58 int l, r, sum, laz;
59 }t[maxn << 2];
60
61 inline void add(int u, int v) {
62 e[++tot].to = v, e[tot].nxt = head[u], head[u] = tot;
63 }
64
65 inline int len(int p) {
66 return t[p].r - t[p].l + 1;
67 }
68
69 inline void push_up(int p) {
70 t[p].sum = (t[ls].sum + t[rs].sum) % mod;
71 }
72
73 inline void push_down(int p) {
74 if (t[p].laz) {
75 t[ls].laz += t[p].laz;
76 t[rs].laz += t[p].laz;
77 t[ls].sum = (t[ls].sum + len(ls) * t[p].laz % mod) % mod;
78 t[rs].sum = (t[rs].sum + len(rs) * t[p].laz % mod) % mod;
79 t[p].laz = 0;
80 }
81 }
82
83 void build(int l, int r, int p) {
84 t[p].l = l, t[p].r = r;
85 if (l == r) {
86 t[p].laz = 0;
87 t[p].sum = rnk[l];
88 return;
89 }
90 int mid = (l + r) >> 1;
91 build(l, mid, ls);
92 build(mid + 1, r, rs);
93 push_up(p);
94 }
95
96 void segupd(int l, int r, int p, int k) {
97 if (l <= t[p].l && t[p].r <= r) {
98 t[p].sum = (t[p].sum + len(p) * k % mod) % mod;
99 t[p].laz += k;
100 return;
101 }
102 int mid = (t[p].l + t[p].r) >> 1;
103 push_down(p);
104 if (l <= mid) segupd(l, r, ls, k);
105 if (mid < r) segupd(l, r, rs, k);
106 push_up(p);
107 }
108
109 int segask(int l, int r, int p) {
110 if (l <= t[p].l && t[p].r <= r) return t[p].sum;
111 int mid = (t[p].l + t[p].r) >> 1;
112 int res = 0;
113 push_down(p);
114 if (l <= mid) res = (res + segask(l, r, ls)) % mod;
115 if (mid < r) res = (res + segask(l, r, rs)) % mod;
116 return res;
117 }
118
119 void dfs1(int u, int f, int depth) {//得到重儿子及一些普通信息
120 deep[u] = depth;
121 fa[u] = f;
122 size[u] = 1;
123 for (int i = head[u]; i; i = e[i].nxt) {
124 int v = e[i].to;
125 if (v == f) continue;
126 dfs1(v, u, depth + 1);
127 if (size[v] > size[son[u]]) son[u] = v;
128 size[u] += size[v];
129 }
130 }
131
132 void dfs2(int u, int topf) {//将重链排列在一起以便线段树维护
133 id[u] = ++cnt;
134 rnk[cnt] = a[u];
135 top[u] = topf;
136 if (!son[u]) return;
137 dfs2(son[u], topf);
138 for (int i = head[u]; i; i = e[i].nxt) {
139 int v = e[i].to;
140 if (v != son[u] && v != fa[u])
141 dfs2(v, v);
142 }
143 }
144
145 void Update(int x, int y, int z) {//类似倍增的方式
146 while (top[x] != top[y]) {
147 if (deep[top[x]] < deep[top[y]]) swap(x, y);
148 segupd(id[top[x]], id[x], 1, z);
149 x = fa[top[x]];
150 }
151 if (deep[x] > deep[y]) swap(x, y);
152 segupd(id[x], id[y], 1, z);
153 }
154
155 int Query(int x, int y) {
156 int ans = 0;
157 while (top[x] != top[y]) {
158 if (deep[top[x]] < deep[top[y]]) swap(x, y);
159 ans = (ans + segask(id[top[x]], id[x], 1)) % mod;
160 x = fa[top[x]];
161 }
162 if (deep[x] > deep[y]) swap(x, y);
163 ans = (ans + segask(id[x], id[y], 1)) % mod;
164 return ans;
165 }
166
167 int main() {
168 n = ri, m = ri, root = ri, mod = ri;
169 rep(i, 1, n) {
170 a[i] = ri;
171 a[i] %= mod;
172 }
173 rep(i, 1, n - 1) {
174 int x = ri, y = ri;
175 add(x, y);
176 add(y, x);
177 }
178 dfs1(root, 0, 1);
179 dfs2(root, root);
180 build(1, n, 1);
181
182 while (m--) {
183 int op = ri, x, y, z;
184 if (op == 1) {
185 x = ri, y = ri, z = ri;
186 Update(x, y, z % mod);//从x到y的最短路径上的节点都加z
187 } else if (op == 2) {
188 x = ri, y = ri;
189 W(Query(x, y));//查询x到y的最短路节点和
190 } else if (op == 3) {
191 x = ri, z = ri;
192 segupd(id[x], id[x] + size[x] - 1, 1, z % mod);//对x的子树全加z
193 } else {
194 x = ri;
195 W(segask(id[x], id[x] + size[x] - 1, 1));//查询x的子树节点和
196 }
197 }
198 return 0;
199 }