树链剖分(未调程序)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6 + 10;
int read() {
int k = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) k = k * 10 + (c ^ 48);
return k * f;
}
struct Edge {
int to, next;
}edge[N];
int n, m, r, mod, idx, tot;
int w[N], wt[N], fa[N], head[N], dep[N], siz[N], hson[N], id[N], top[N];
void add (int u, int v) {
edge[idx].to = v;
edge[idx].next = head[u];
head[u] = idx++;
}
// ----------------------------------线段树部分-------------------------------------------------------------
struct node {
int data, left, right, lazy;
}a[N];
void push_down (int Root) {
a[Root * 2].data += a[Root * 2].lazy * (a[Root * 2].right - a[Root * 2].left + 1);
a[Root * 2].lazy += a[Root].lazy;
a[Root * 2 + 1].data += a[Root * 2 + 1].lazy * (a[Root * 2 + 1].right - a[Root * 2 + 1].left + 1);
a[Root * 2 + 1].lazy += a[Root].lazy;
a[Root * 2].data %= mod;
a[Root * 2 + 1].data %= mod;
a[Root].lazy = 0;
}
void build (int Root, int Left, int Right) {
a[Root].left = Left;a[Root].right = Right;
if (a[Root].left == a[Root].right) {
int temp = wt[Left];
a[Root].data = temp > mod ? temp % mod : temp;
return ;
}
int mid = (Left + Right) >> 1;
build (Root, Left, mid);
build (Root, mid + 1, Right);
}
void modify (int Root, int Left, int Right, int k) {
if (Left <= a[Root].left && Right >= a[Root].right) {
a[Root].lazy += k;
a[Root].data += (a[Root].right - a[Root].left + 1) * k;
return;
}
push_down(Root);
if (a[Root * 2].right >= Left) modify(Root* 2, Left, Right, k);
if (a[Root * 2 + 1].left <= Right) modify(Root * 2 + 1, Left, Right, k);
a[Root].data = a[Root * 2].data + a[Root * 2 + 1].data;
}
int query (int Root, int Left, int Right) {
if (a[Root].right <= Right && a[Root].left >= Left) return a[Root].data;
push_down(Root);
int ans = 0;
if (a[Root * 2].right >= Left) ans += query (Root * 2, Left, Right);
if (a[Root * 2 + 1].left <= Right) ans += query (Root * 2 + 1, Left, Right);
return ans;
}
// -----------------------------------树链剖分部分---------------------------------------------------------------
int rs;
void dfs1(int u, int father, int deepth) {
dep[u] = dep[father] + 1;
fa[u] = father;
siz[u] = 1;
int maxson = -1;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (v == father) continue;
dfs1 (v, u, deepth + 1);
siz[u] = siz[v] + 1;
if (siz[v] > maxson) {
hson[u] = v;
maxson = siz[v];
}
}
}
void dfs2 (int u, int father) {
id[u] = ++tot;
wt[u] = w[u];
top[u] = father;
dfs2 (hson[u], u);
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].to;
if (v == father || v == hson[u]) continue;
dfs2 (v, v);
}
}
int qRange (int x, int y) {
int ans = 0;
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x, y);
rs = 0;
query(1, id[top[x]], id[x]);
ans += rs;
ans %= mod;
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
rs = 0;
query (1, id[x], id[y]);
ans += rs;
return ans % mod;
}
void updRange(int x, int y, int z) {
z %= mod;
while (top[x] != top[y]) {
if (dep[x] > dep[y]) swap(x, y);
modify(1, id[top[x]], id[x], z);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
modify(1, id[x], id[y], z);
}
int qson(int x){
rs=0;
query(1,id[x],id[x]+siz[x]-1);
return rs;
}
void updson(int x,int k){
modify(1,id[x],id[x]+siz[x]-1,k);
}
//---------------------------------------------------------------------------------------------------
int main() {
memset(head, -1, sizeof(head));
n = read(); m = read(); r = read(); mod = read();
for (int i = 1; i <= n; i++) cin >> w[i];
for (int i = 1; i < n; i++) {
int x = read(), y = read();
add (x, y);
add (y, x);
}
dfs1 (r, 0, 1);
dfs2 (r, r);
build (1, 1, n);
while (m --) {
int opt = read();
if (opt == 1) {
int x = read(), y = read(), z = read();
updRange(x, y, z);
}
else if (opt == 2) {
int x = read(), y = read();
cout << qRange(x, y) << '\n';
}
else if (opt == 3) {
int x = read(), y = read();
updson(x, y);
}
else {
int x = read();
cout << qson(x) << '\n';
}
}
return 0;
}