Description
n
≤
3
e
5
,
q
≤
5
e
5
n\le3e5,q\le5e5
n ≤ 3 e 5 , q ≤ 5 e 5
Solution
考虑维护每一个黑点,如果没有修改,子树查询可以把子树内的每一个黑点的
w
∗
c
n
t
w*cnt
w ∗ c n t 求和,再考虑这个点的归属点权值
v
v
v ,贡献
v
∗
(
s
z
x
−
∑
c
n
t
)
v*(sz_x-\sum cnt)
v ∗ ( s z x − ∑ c n t ) ,单点查询可以直接询问归属点的权值,用一个线段树维护上面的值,以及4操作。 如果有加入黑点的操作,简单维护一下上面的东西,把新黑点的权值变为它的归属点的权值。 如果有加入白点的操作,还要把这个点的权值贡献到子树内,可以直接子树加,然后再做一次4操作容斥掉。 查询一个点的归属点可以链剖+set,查询当前重链最浅的点,再二分。
O
(
n
l
o
g
n
)
O(n\ log\ n)
O ( n l o g n )
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#define maxn 300005
#define uint unsigned int
using namespace std;
int n, q, i, j, k, fa[ maxn] ;
int em, e[ maxn] , nx[ maxn] , ls[ maxn] ;
int tot, dfn[ maxn] , top[ maxn] , Idfn[ maxn] , sz[ maxn] , g[ maxn] , dep[ maxn] ;
void read ( int & x) {
x= 0 ; char ch= getchar ( ) ;
for ( ; ch< '0' || ch> '9' ; ch= getchar ( ) ) ;
for ( ; ch>= '0' && ch<= '9' ; ch= getchar ( ) ) x= x* 10 + ch- '0' ;
}
void insert ( int x, int y) {
em++ ; e[ em] = y; nx[ em] = ls[ x] ; ls[ x] = em;
}
struct Treearray{
uint s[ maxn] ;
void add ( int x, uint d) { for ( ; x<= n; x+ = x& - x) s[ x] + = d; }
uint sum ( int x, uint S= 0 ) { for ( ; x; x- = x& - x) S+ = s[ x] ; return S; }
uint query ( int l, int r) { return sum ( r) - sum ( l- 1 ) ; }
} ;
struct data{
Treearray K, B;
void add ( int l, int r, uint d) {
K. add ( l, d) , K. add ( r+ 1 , - d) ;
B. add ( l, d* ( - l+ 1 ) ) , B. add ( r+ 1 , - d* ( - l+ 1 ) ) ;
B. add ( r+ 1 , d* ( r- l+ 1 ) ) ;
}
uint query ( int l, int r) {
return K. sum ( r) * r+ B. sum ( r) - K. sum ( l- 1 ) * ( l- 1 ) - B. sum ( l- 1 ) ;
}
} ps;
void dfs1 ( int x, int p) {
sz[ x] = 1 ;
for ( int i= ls[ x] ; i; i= nx[ i] ) {
dfs1 ( e[ i] , x) , sz[ x] + = sz[ e[ i] ] ;
if ( ! g[ x] || sz[ e[ i] ] > sz[ g[ x] ] ) g[ x] = e[ i] ;
}
}
void dfs2 ( int x, int p) {
if ( p== 0 ) top[ x] = x;
dfn[ x] = ++ tot, Idfn[ tot] = x, dep[ x] = dep[ p] + 1 ;
if ( g[ x] ) top[ g[ x] ] = top[ x] , dfs2 ( g[ x] , x) ;
for ( int i= ls[ x] ; i; i= nx[ i] ) if ( e[ i] != g[ x] )
top[ e[ i] ] = e[ i] , dfs2 ( e[ i] , x) ;
}
set< int > d[ maxn] ;
set< int > : : iterator it;
int gettop ( int x) {
while ( 1 ) {
if ( ! d[ top[ x] ] . empty ( ) ) {
if ( * d[ top[ x] ] . begin ( ) <= dep[ x] ) {
it= d[ top[ x] ] . upper_bound ( dep[ x] ) ;
it-- ;
return Idfn[ dfn[ x] - ( dep[ x] - ( * it) ) ] ;
}
}
x= fa[ top[ x] ] ;
}
}
int col[ maxn] ;
uint ts[ maxn* 4 ] , tc[ maxn* 4 ] , tv[ maxn* 4 ] , tag[ maxn* 4 ] ;
void upd ( int x) {
ts[ x] = ts[ x<< 1 ] + ts[ x<< 1 ^ 1 ] ;
tc[ x] = tc[ x<< 1 ] + tc[ x<< 1 ^ 1 ] ;
tv[ x] = tv[ x<< 1 ] + tv[ x<< 1 ^ 1 ] ;
}
void downtag ( int x, int l, int r) {
if ( ! tag[ x] ) return ;
tv[ x] + = tag[ x] ;
ts[ x] + = tag[ x] * tc[ x] ;
if ( l< r) tag[ x<< 1 ] + = tag[ x] , tag[ x<< 1 ^ 1 ] + = tag[ x] ;
tag[ x] = 0 ;
}
void changev ( int x, int l, int r, int L, int R, uint d) {
downtag ( x, l, r) ;
if ( l> R|| r< L) return ;
if ( L<= l&& r<= R) {
tag[ x] + = d, downtag ( x, l, r) ;
return ;
}
int mid= ( l+ r) >> 1 ;
changev ( x<< 1 , l, mid, L, R, d) ;
changev ( x<< 1 ^ 1 , mid+ 1 , r, L, R, d) ;
upd ( x) ;
}
void changec ( int x, int l, int r, int p, uint d) {
downtag ( x, l, r) ;
if ( r< p|| l> p) return ;
if ( l== p&& l== r) {
tc[ x] + = d, ts[ x] + = d* tv[ x] ;
return ;
}
int mid= ( l+ r) >> 1 ;
changec ( x<< 1 , l, mid, p, d) ;
changec ( x<< 1 ^ 1 , mid+ 1 , r, p, d) ;
upd ( x) ;
}
uint getv ( int x, int l, int r, int p) {
downtag ( x, l, r) ;
if ( l== p&& l== r) return tv[ x] ;
int mid= ( l+ r) >> 1 ;
if ( p<= mid) return getv ( x<< 1 , l, mid, p) ;
else return getv ( x<< 1 ^ 1 , mid+ 1 , r, p) ;
}
uint getc ( int x, int l, int r, int L, int R) {
if ( l> R|| r< L) return 0 ;
if ( L<= l&& r<= R) return tc[ x] ;
int mid= ( l+ r) >> 1 ;
return getc ( x<< 1 , l, mid, L, R) + getc ( x<< 1 ^ 1 , mid+ 1 , r, L, R) ;
}
uint gets ( int x, int l, int r, int L, int R) {
downtag ( x, l, r) ;
if ( l> R|| r< L) return 0 ;
if ( L<= l&& r<= R) return ts[ x] ;
int mid= ( l+ r) >> 1 ;
return gets ( x<< 1 , l, mid, L, R) + gets ( x<< 1 ^ 1 , mid+ 1 , r, L, R) ;
}
void coverv ( int x, int l, int r, int p, uint v) {
downtag ( x, l, r) ;
if ( r< p|| l> p) return ;
if ( l== p&& l== r) { tv[ x] = v; ts[ x] = v* tc[ x] ; return ; }
int mid= ( l+ r) >> 1 ;
coverv ( x<< 1 , l, mid, p, v) , coverv ( x<< 1 ^ 1 , mid+ 1 , r, p, v) ;
upd ( x) ;
}
void reverse ( int x) {
if ( col[ x] ) {
col[ x] = 0 ;
int cnt= sz[ x] - getc ( 1 , 1 , n, dfn[ x] + 1 , dfn[ x] + sz[ x] - 1 ) ;
int y= gettop ( fa[ x] ) ; d[ top[ x] ] . erase ( dep[ x] ) ;
uint vx= getv ( 1 , 1 , n, dfn[ x] ) ;
uint vy= getv ( 1 , 1 , n, dfn[ y] ) ;
changec ( 1 , 1 , n, dfn[ x] , - cnt) , coverv ( 1 , 1 , n, dfn[ x] , 0 ) ;
changec ( 1 , 1 , n, dfn[ y] , cnt) ;
ps. add ( dfn[ x] , dfn[ x] + sz[ x] - 1 , vx- vy) ;
changev ( 1 , 1 , n, dfn[ x] , dfn[ x] + sz[ x] - 1 , - ( vx- vy) ) ;
} else {
col[ x] = 1 ;
int cnt= sz[ x] - getc ( 1 , 1 , n, dfn[ x] + 1 , dfn[ x] + sz[ x] - 1 ) ;
int y= gettop ( x) ; d[ top[ x] ] . insert ( dep[ x] ) ;
uint vy= getv ( 1 , 1 , n, dfn[ y] ) ;
changec ( 1 , 1 , n, dfn[ x] , cnt) ;
changec ( 1 , 1 , n, dfn[ y] , - cnt) ;
coverv ( 1 , 1 , n, dfn[ x] , vy) ;
}
}
int main ( ) {
freopen ( "ceshi.in" , "r" , stdin ) ;
freopen ( "ceshi.out" , "w" , stdout ) ;
read ( n) , read ( q) ;
for ( i= 2 ; i<= n; i++ ) read ( fa[ i] ) , insert ( fa[ i] , i) ;
dfs1 ( 1 , 0 ) , dfs2 ( 1 , 0 ) ;
int cnt= 0 ;
col[ 1 ] = 1 , changec ( 1 , 1 , n, dfn[ 1 ] , sz[ 1 ] ) , d[ 1 ] . insert ( 1 ) ;
while ( q-- ) {
int tp, x; read ( tp) , read ( x) ;
if ( tp== 1 )
printf ( "%u\n" , getv ( 1 , 1 , n, dfn[ gettop ( x) ] ) + ps. query ( dfn[ x] , dfn[ x] ) ) ;
if ( tp== 2 )
read ( k) , changev ( 1 , 1 , n, dfn[ x] , dfn[ x] , k) ;
if ( tp== 3 ) {
uint ans= getv ( 1 , 1 , n, dfn[ gettop ( x) ] ) * ( sz[ x] - getc ( 1 , 1 , n, dfn[ x] + 1 , dfn[ x] + sz[ x] - 1 ) ) ;
ans+ = ps. query ( dfn[ x] , dfn[ x] + sz[ x] - 1 ) ;
ans+ = gets ( 1 , 1 , n, dfn[ x] + 1 , dfn[ x] + sz[ x] - 1 ) ;
printf ( "%u\n" , ans) ;
}
if ( tp== 4 )
read ( k) , changev ( 1 , 1 , n, dfn[ x] , dfn[ x] + sz[ x] - 1 , k) ;
if ( tp== 5 || tp== 6 )
reverse ( x) ;
}
}