太久没写过板子都有点不熟了,今天打一下发现还是有些小问题,水篇blog警醒一下。
修改链、子树,查询链、子树和。
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100005;
int n, m, r, p;
int TR[N*4], tag[N*4], a[N], qwq[N];
int tov[N*2], nex[N*2], h[N], stot;
void add ( int u, int v ) {
tov[++stot] = v;
nex[stot] = h[u];
h[u] = stot;
}
void update ( int nd ) {
TR[nd] = ( TR[nd << 1] + TR[nd << 1 | 1] ) % p;
}
void push_down ( int nd, int l, int r ) {
if ( tag[nd] ) {
int mid = ( l + r ) >> 1;
TR[nd << 1] = ( TR[nd << 1] + tag[nd] * ( mid - l + 1 ) % p ) % p;
TR[nd << 1 | 1] = ( TR[nd << 1 | 1] + tag[nd] * ( r - mid ) % p ) % p;
tag[nd << 1] = ( tag[nd << 1] + tag[nd] ) % p;
tag[nd << 1 | 1] = ( tag[nd << 1 | 1] + tag[nd] ) % p;
tag[nd] = 0;
}
}
void build ( int nd, int l, int r ) {
if ( l == r ) {
TR[nd] = qwq[l]; ///////////////////////
return ;
}
int mid = ( l + r ) >> 1;
build ( nd << 1, l, mid );
build ( nd << 1 | 1, mid + 1, r );
update ( nd ); ///
}
int fa[N], siz[N], dep[N], son[N];
void dfs1 ( int u, int f ) {
fa[u] = f;
siz[u] = 1;
dep[u] = dep[f] + 1;
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == f ) continue;
dfs1 ( v, u );
siz[u] += siz[v];
if ( siz[v] > siz[son[u]] ) son[u] = v;
}
}
int in[N], top[N], ti, out[N];
void dfs2 ( int u, int tp ) {
top[u] = tp;
in[u] = ++ ti;
qwq[ti] = a[u]; ///////////////////////////
if ( son[u] ) dfs2 ( son[u], tp );
for ( int i = h[u]; i; i = nex[i] ) {
int v = tov[i];
if ( v == fa[u] || v == son[u] ) continue;
dfs2 ( v, v );
}
out[u] = ti; //////////////////////////
}
void add ( int nd, int L, int R, int l, int r, int delta ) {
if ( l >= L && r <= R ) {
TR[nd] = ( TR[nd] + delta * ( r - l + 1 ) % p ) % p; ////////////
tag[nd] = ( tag[nd] + delta ) % p;
return ;
}
push_down ( nd, l, r );
int mid = ( l + r ) >> 1;
if ( L <= mid ) add ( nd << 1, L, R, l, mid, delta );
if ( R > mid ) add ( nd << 1 | 1, L, R, mid + 1, r, delta );
update ( nd );
}
void add ( int u, int v, int delta ) {
while ( top[u] != top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) swap ( u, v );
add ( 1, in[top[u]], in[u], 1, n, delta );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u, v );
add ( 1, in[v], in[u], 1, n, delta );
}
int query ( int nd, int L, int R, int l, int r ) {
if ( l >= L && r <= R ) return TR[nd];
push_down ( nd, l, r );
int ans = 0;
int mid = ( l + r ) >> 1;
if ( L <= mid ) ans = ( ans + query ( nd << 1, L, R, l, mid ) ) % p;
if ( R > mid ) ans = ( ans + query ( nd << 1 | 1, L, R, mid + 1, r ) ) % p;
return ans;
}
int query ( int u, int v ) {
int ans = 0;
while ( top[u] != top[v] ) {
if ( dep[top[u]] < dep[top[v]] ) swap ( u, v );
ans = ( ans + query ( 1, in[top[u]], in[u], 1, n ) ) % p;
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u, v );
ans = ( ans + query ( 1, in[v], in[u], 1, n ) ) % p;
return ans;
}
void add_ ( int u, int delta ) {
add ( 1, in[u], out[u], 1, n, delta );
}
int query_ ( int u ) {
return query ( 1, in[u], out[u], 1, n );
}
int main ( ) {
scanf ( "%d%d%d%d", &n, &m, &r, &p );
for ( int i = 1; i <= n; i ++ )
scanf ( "%d", &a[i] );
for ( int i = 1; i < n; i ++ ) {
int x, y;
scanf ( "%d%d", &x, &y );
add ( x, y );
add ( y, x );
}
dfs1 ( r, r );
dfs2 ( r, r );
build ( 1, 1, n ); /////线段树根节点是1
for ( int i = 1; i <= m; i ++ ) {
int opt;
scanf ( "%d", &opt );
if ( opt == 1 ) {
int x, y, z;
scanf ( "%d%d%d", &x, &y, &z );
add ( x, y, z );
} else if ( opt == 2 ) {
int x, y;
scanf ( "%d%d", &x, &y );
printf ( "%d\n", query ( x, y ) );
} else if ( opt == 3 ) {
int x, y;
scanf ( "%d%d", &x, &y );
add_ ( x, y );
} else {
int x;
scanf ( "%d", &x );
printf ( "%d\n", query_ ( x ) );
}
}
return 0;
}