#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define lson rt<<1, l, mid #define rson rt<<1|1, mid+1, r using namespace std; const int maxn = 500100; int P; typedef long long ll; struct Edge { int to, next; }edges[maxn*2]; int head[maxn], tot; int n; ll w[maxn]; int fa[maxn], son[maxn], siz[maxn], dep[maxn]; int top[maxn], id[maxn], rk[maxn], cnt; // son[u]: u的重儿子 // top[u]: u所在链的顶端节点 // // id[u]: 树链剖分后节点的新编号 // rk[u]: dfs编号对应的节点 rk[id[u]] = u // cnt : dfs序 void add(int u, int v) { edges[++tot].to = v; edges[tot].next = head[u]; head[u] = tot; } // 求fa, siz, dep, son void dfs1(int u) { siz[u] = 1; for(int i=head[u];i;i=edges[i].next) { int v = edges[i].to; if(v==fa[u]) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs1(v); siz[u] += siz[v]; if(siz[v]>siz[son[u]]) son[u] = v; } } // 连接重链 void dfs2(int u, int topf) { id[u] = ++cnt; rk[cnt] = u; top[u] = topf; if(!son[u]) return; dfs2(son[u], topf); // 重链先dfs,保证重链上各节点dfs序连续 for(int i=head[u];i;i=edges[i].next) { int v = edges[i].to; if(v!=fa[u] && v!=son[u]) // 不是重儿子,轻链 dfs2(v, v); } } /* 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 */ ll sum[maxn*4], lazy[maxn*4]; void build(int rt, int l, int r) { if(l!=r) { int mid = (l+r)/2; build(lson); build(rson); sum[rt] = (sum[rt<<1] + sum[rt<<1|1]) % P; } else { sum[rt] = w[rk[l]]; lazy[rt] = 0; } } void pushDown(int rt, int len) { if(lazy[rt]) { (sum[rt<<1] += (len-(len>>1)) * lazy[rt] % P) %= P; (sum[rt<<1|1] += (len>>1) * lazy[rt] % P) %= P; (lazy[rt<<1] += lazy[rt]) %= P; (lazy[rt<<1|1] += lazy[rt]) %= P; lazy[rt] = 0; } } void update(int rt, int l, int r, int L, int R, ll add) { if(L<=l && R>=r) { (lazy[rt] += add) %= P; (sum[rt] += (r-l+1)*add) %= P; return; } int mid = (l+r)/2; pushDown(rt, r-l+1); if(L<=mid) update(lson, L, R, add); if(R>mid) update(rson, L, R, add); sum[rt] = (sum[rt<<1] + sum[rt<<1|1]) % P; } ll query(int rt, int l, int r, int L, int R) { if(L<=l && R>=r) return sum[rt]; ll res = 0; int mid = (l+r)/2; pushDown(rt, r-l+1); if(L<=mid) res += query(lson, L, R) % P; if(R>mid) res += query(rson, L, R) % P; return res % P; } // 操作1 void updatePath(int x, int y, ll z) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x, y); update(1, 1, n, id[top[x]], id[x], z); x = fa[top[x]]; } if(dep[x]>dep[y]) swap(x, y); update(1, 1, n, id[x], id[y], z); } // 操作3 void updateSon(int x, ll z) { update(1, 1, n, id[x], id[x]+siz[x]-1, z); } // 操作2 ll queryPath(int x, int y) { ll res = 0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x, y); res = (res + query(1, 1, n, id[top[x]], id[x])) % P; x = fa[top[x]]; } if(dep[x]>dep[y]) swap(x, y); res = (res + query(1, 1, n, id[x], id[y])) % P; return res; } // 操作4 ll qeurySon(int x) { return query(1, 1, n, id[x], id[x]+siz[x]-1); } int main() { int M, R; cin>>n>>M>>R>>P; for(int i=1;i<=n;i++) { scanf("%lld", &w[i]); } for(int i=0;i<n-1;i++) { int u, v; scanf("%d %d", &u, &v); add(u, v); add(v, u); } dfs1(R); dfs2(R, R); build(1, 1, n); while(M--) { int op, x, y; ll z; scanf("%d", &op); if(op==1) { scanf("%d %d %lld", &x, &y, &z); updatePath(x, y, z); } else if(op==2) { scanf("%d %d", &x, &y); printf("%lld ", queryPath(x, y)); } else if(op==3) { scanf("%d %lld", &x, &z); updateSon(x, z); } else { scanf("%d", &x); printf("%lld ", qeurySon(x)); } } return 0; }