P7446 [Ynoi2007] rfplca
因为是 Ynoi 所以 我们考虑分块来维护 \(a_i\)
对于每个位置维护两个值 \(fa_i\) 和 \(top_i\) ,分别表示它的真实祖先和块外的第一个祖先。
对于每次修改
-
散块直接暴力修改,暴力重构块内的 \(top_i\)
-
整块整体打标记 \(sub\) , 表示这个块被减了多少。
注意到一个块修改 \(\sqrt n\) 次后所有 \(top_i = fa_i\) ,此时就不需要重构了(当然标记还是正常打)
一共有 \(\sqrt n\) 个块 ,每个块重构 \(\sqrt n\) 次,每次重构复杂度为 \(\sqrt n\) ,总复杂度便为 \(n \sqrt n\)
询问像树剖一样跳就可以了。
复杂度 \(\mathcal O((n+q)\sqrt n)\)
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define LL long long
const int MAXN = 4e5 , MAXS = 650;
int n , m , q , fa[ MAXN + 5 ] , bel[ MAXN + 5 ] , l[ MAXS + 5 ] , r[ MAXS + 5 ];
int top[ MAXN + 5 ] , cnt[ MAXS + 5 ]; LL sub[ MAXS + 5 ];
void ReBuild( int id ) {
for( int i = l[ id ] ; i <= r[ id ] ; i ++ ) fa[ i ] = max( fa[ i ] - sub[ id ] , 1ll ); sub[ id ] = 0;
for( int i = l[ id ] ; i <= r[ id ] ; i ++ ) {
if( fa[ i ] < l[ id ] ) top[ i ] = fa[ i ];
else top[ i ] = top[ fa[ i ] ];
}
}
void Update( int l , int r , int val ) {
int ql = bel[ l ] , qr = bel[ r ];
if( ql == qr ) {
for( int i = l ; i <= r ; i ++ ) fa[ i ] = max( fa[ i ] - val , 1 );
ReBuild( ql ); return;
}
for( int i = ql + 1 ; i <= qr - 1 ; i ++ ) {
sub[ i ] += val; cnt[ i ] ++;
if( cnt[ i ] <= MAXS ) ReBuild( i );
}
for( ; bel[ l ] == ql ; l ++ ) fa[ l ] = max( 1 , fa[ l ] - val );
for( ; bel[ r ] == qr ; r -- ) fa[ r ] = max( 1 , fa[ r ] - val );
ReBuild( ql ); ReBuild( qr );
}
#define BS( u ) ( max( fa[ u ] - sub[ bel[ u ] ] , 1ll ) )
#define GS( u ) ( max( top[ u ] - sub[ bel[ u ] ] , 1ll ) )
int lca( int u , int v ) {
for( ; bel[ u ] != bel[ v ] ; u = GS( u ) ) if( bel[ u ] < bel[ v ] ) swap( u , v );
for( ; GS( u ) != GS( v ) ; u = GS( u ) ) if( u < v ) swap( u , v );
for( ; u != v ; u = BS( u ) ) if( u < v ) swap( u , v );
return u;
}
int main( ) {
scanf("%d %d",&n,&q); m = ( n - 1 ) / MAXS + 1;
for( int i = 2 ; i <= n ; i ++ ) scanf("%d",&fa[ i ]);
for( int i = 1 ; i <= n ; i ++ ) bel[ i ] = ( i - 1 ) / MAXS + 1 , r[ bel[ i ] ] = i;
for( int i = 1 ; i <= m ; i ++ ) l[ i ] = r[ i - 1 ] + 1;
for( int i = 1 ; i <= m ; i ++ ) ReBuild( i );
for( int i = 1 , opt , l , r , x , lst = 0 ; i <= q ; i ++ ) {
scanf("%d %d %d",&opt,&l,&r); l ^= lst , r ^= lst;
if( opt == 1 ) scanf("%d",&x) , Update( l , r , x ^ lst );
if( opt == 2 ) printf("%d\n", lst = lca( l , r ) );
}
return 0;
}