码风偏丑,请谅解
#include <cstdio>
#define re register
#define get getchar()
inline int read(){
re int x = 0;re char c = get;
while (c < '0' || c > '9') c = get;
while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = get;}
return x;
}
const int MAXN = 2e5 + 1;
const int n = read();
const int m = read();
const int r = read();
const int mod = read();
struct node{
int next , to;
}e[MAXN];
int head[MAXN] , w[MAXN] , wt[MAXN] , tot;
int a[MAXN << 2] , tag[MAXN << 2];
int son[MAXN] , id[MAXN] , fa[MAXN] , dep[MAXN] , sz[MAXN] , top[MAXN] , lim;
inline void swap(re int &x , re int &y){x ^= y ^= x ^= y;}
inline void add(re int u , re int v){
e[++ tot].next = head[u];
e[tot].to = v;
head[u] = v;
}
inline int ls(re int p){return p << 1;}
inline int rs(re int p){return p << 1 | 1;}
inline void push_up(re int p){a[p] = a[ls(p)] + a[rs(p)] % mod;}
inline void f(re int p , re int l , re int r , re int k){
tag[p] += k;
(a[p] += k * (r - l + 1)) %= mod;
}
inline void push_down(re int p , re int l , re int r){
re int mid = (l + r) >> 1;
f(ls(p) , l , mid , tag[p]);
f(rs(p) , mid + 1 , r , tag[p]);
tag[p] = 0;
}
inline void build(re int p , re int l , re int r){
if (l == r){
(a[p] = wt[l]) %= mod;
return ;
}
re int mid = (l + r) >> 1;
build(ls(p) , l , mid);
build(rs(p) , mid + 1 , r);
push_up(p);
}
inline void update(re int p , re int l , re int r , re int nl , re int nr , re int k){
if (nl <= l && r <= nr){
f(p , l , r , k);
return ;
}
push_down(p , l , r);
re int mid = (l + r) >> 1;
if (nl <= mid) update(ls(p) , l , mid , nl , nr , k);
if (nr > mid) update(rs(p) , mid + 1 , r , nl , nr , k);
push_up(p);
}
inline int query(re int p , re int l , re int r , re int nl , re int nr){
if (nl <= l && r <= nr) return a[p];
re int res = 0;
push_down(p , l , r);
re int mid = (l + r) >> 1;
if (nl <= mid) res += query(ls(p) , l , mid , nl , nr);
if (nr > mid) res += query(rs(p) , mid + 1 , r , nl , nr);
return res;
}
inline int range(re int x , re int y){
re int ans = 0;
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x , y);
(ans += query(1 , 1 , n , id[top[x]] , id[x])) %= mod;
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x , y);
return (ans += query(1 , 1 , n , id[x] , id[y])) %= mod;
}
inline void update_range(re int x , re int y , re int k){
k %= mod;
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x , y);
update(1 , 1 , n , id[top[x]] , id[x] , k);
x = fa[top[x]];
}
if (dep[x] > dep[y]) swap(x , y);
update(1 , 1 , n , id[x] , id[y] , k);
}
inline int qson(re int x){return query(1 , 1 , n , id[x] , id[x] + sz[x] - 1);}
inline void update_son(re int x , re int k){update(1 , 1 , n , id[x] , id[x] + sz[x] - 1 , k);}
inline void dfs1(re int now , re int fath , re int deep){
dep[now] = deep;fa[now] = fath;sz[now] = 1;
re int maxson = -1;
for (re int i = head[now]; i ;i = e[i].next){
re int y = e[i].to;
if (y == fath) continue;
dfs1(y , now , deep + 1);
sz[now] += sz[y];
if (sz[y] > maxson) son[now] = y , maxson = sz[y];
}
}
inline void dfs2(re int now , re int topf){
id[now] = ++ lim;wt[lim] = w[now];top[now] = topf;
if (!son[now]) return ;
dfs2(son[now] , topf);
for (re int i = head[now]; i ;i = e[i].next){
re int y = e[i].to;
if (y == fa[now] || y == son[now]) continue;
dfs2(y , y);
}
}
signed main(){
for (re int i = 1;i <= n;++ i) w[i] = read();
for (re int i = 1;i < n;++ i){
re int u = read() , v = read();
add(u , v);add(v , u);
}
dfs1(r , 0 , 1);
// puts("finish:dfs1");
dfs2(r , r);
// puts("finish:dfs2");
build(1 , 1 , n);
// puts("finish:build");
for (re int i = 1;i <= m;++ i){
re int opt = read() , x , y , z;
switch (opt){
case 1:x = read() , y = read() , z = read();update_range(x , y , z);break;
case 2:x = read() , y = read();printf("%d\n" , range(x , y));break;
case 3:x = read() , y = read();update_son(x , y);break;
default:x = read();printf("%d\n" , qson(x));break;
}
}
return 0;
}