已知一棵包含 NN 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
1 x y z,表示将树从 xx 到 yy 结点最短路径上所有节点的值都加上 zz。
2 x y,表示求树从 xx 到 yy 结点最短路径上所有节点的值之和。
3 x z,表示将以 xx 为根节点的子树内所有节点值都加上 zz。
4 x 表示求以 xx 为根节点的子树内所有节点值之和
#include <bits/stdc++.h>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
typedef long long ll;
const int maxn= 5e5 + 100 ;
int n, m, r, mod, tot, a[ maxn] , siz[ maxn] , fa[ maxn] , son[ maxn] , id[ maxn] , idd[ maxn] , sum[ maxn<< 2 ] , top[ maxn] , lazy[ maxn<< 2 ] , deep[ maxn] ;
vector< int > mp[ maxn] ;
void dfs1 ( int x, int f, int d) {
siz[ x] = 1 ;
fa[ x] = f;
deep[ x] = d;
son[ x] = 0 ;
for ( auto y: mp[ x] ) {
if ( y== f) continue ;
dfs1 ( y, x, d+ 1 ) ;
siz[ x] + = siz[ y] ;
if ( siz[ son[ x] ] < siz[ y] ) son[ x] = y;
}
}
void dfs2 ( int x, int root) {
id[ x] = ++ tot;
idd[ tot] = a[ x] ;
top[ x] = root;
if ( son[ x] ) dfs2 ( son[ x] , root) ;
for ( auto y: mp[ x] ) {
if ( y!= fa[ x] && y!= son[ x] ) dfs2 ( y, y) ;
}
}
void build ( int rt, int l, int r) {
if ( l== r) {
sum[ rt] = idd[ l] % mod;
return ;
}
int mid= ( l+ r) >> 1 ;
build ( lson) ;
build ( rson) ;
sum[ rt] = ( sum[ rt<< 1 ] + sum[ rt<< 1 | 1 ] ) % mod;
}
void pushdown ( int rt, int l, int r) {
if ( lazy[ rt] ) {
int mid= ( l+ r) >> 1 ;
sum[ rt<< 1 ] + = lazy[ rt] * ( mid- l+ 1 ) ;
sum[ rt<< 1 ] % = mod;
sum[ rt<< 1 | 1 ] + = lazy[ rt] * ( r- mid) ;
sum[ rt<< 1 | 1 ] % = mod;
lazy[ rt<< 1 ] + = lazy[ rt] ;
lazy[ rt<< 1 | 1 ] + = lazy[ rt] ;
lazy[ rt] = 0 ;
}
}
void update ( int rt, int l, int r, int x, int y, int val) {
if ( x<= l&& r<= y) {
lazy[ rt] + = val;
sum[ rt] + = val* ( r- l+ 1 ) ;
return ;
}
int mid= ( l+ r) >> 1 ;
pushdown ( rt, l, r) ;
if ( x<= mid) update ( lson, x, y, val) ;
if ( y> mid) update ( rson, x, y, val) ;
sum[ rt] = ( sum[ rt<< 1 ] + sum[ rt<< 1 | 1 ] ) % mod;
}
int query ( int rt, int l, int r, int x, int y) {
if ( x<= l&& r<= y) return sum[ rt] ;
int mid= ( l+ r) >> 1 , ans= 0 ;
pushdown ( rt, l, r) ;
if ( x<= mid) ans= ( ans+ query ( lson, x, y) ) % mod;
if ( y> mid) ans= ( ans+ query ( rson, x, y) ) % mod;
return ans;
}
int getdis ( int x, int y) {
int ans= 0 ;
while ( top[ x] != top[ y] ) {
if ( deep[ top[ x] ] < deep[ top[ y] ] ) swap ( x, y) ;
ans+ = query ( 1 , 1 , n, id[ top[ x] ] , id[ x] ) ;
ans% = mod;
x= fa[ top[ x] ] ;
}
if ( deep[ x] > deep[ y] ) swap ( x, y) ;
ans+ = query ( 1 , 1 , n, id[ x] , id[ y] ) ;
return ans% mod;
}
void upday ( int x, int y, int val) {
while ( top[ x] != top[ y] ) {
if ( deep[ top[ x] ] < deep[ top[ y] ] ) swap ( x, y) ;
update ( 1 , 1 , n, id[ top[ x] ] , id[ x] , val) ;
x= fa[ top[ x] ] ;
}
if ( deep[ x] > deep[ y] ) swap ( x, y) ;
update ( 1 , 1 , n, id[ x] , id[ y] , val) ;
}
int main ( ) {
scanf ( "%d%d%d%d" , & n, & m, & r, & mod) ;
for ( int i= 1 ; i<= n; i++ )
scanf ( "%d" , & a[ i] ) ;
for ( int i= 1 , x, y; i< n; i++ ) {
scanf ( "%d%d" , & x, & y) ;
mp[ x] . push_back ( y) , mp[ y] . push_back ( x) ;
}
dfs1 ( r, 0 , 1 ) ;
dfs2 ( r, r) ;
build ( 1 , 1 , n) ;
while ( m-- ) {
int op, x, y, z;
scanf ( "%d" , & op) ;
if ( op== 3 ) {
scanf ( "%d%d" , & x, & z) ;
update ( 1 , 1 , n, id[ x] , id[ x] + siz[ x] - 1 , z) ;
}
else if ( op== 4 ) {
scanf ( "%d" , & x) ;
printf ( "%d\n" , query ( 1 , 1 , n, id[ x] , id[ x] + siz[ x] - 1 ) ) ;
}
else if ( op== 1 ) {
scanf ( "%d%d%d" , & x, & y, & z) ;
upday ( x, y, z% mod) ;
}
else {
scanf ( "%d%d" , & x, & y) ;
printf ( "%d\n" , getdis ( x, y) ) ;
}
}
}