bzoj 3343 分块

  因为询问比较少,所以我们可以将n个数分成sqrt(n)个块,每个块用一颗bst存一下,然后对于修改l,r,我们将l,r区间中整块的直接在bst上打一个标签,对于不是整块的我们直接暴力修改,对于询问l,r,仍然是整块的直接在bst中求大于c的个数(考虑标签),然后不是整块的部分暴力扫一遍更新答案。

  我写的sbt,可能是sbt常数比较大什么的,tle了,其实对于每一个块我们可以快排保存,然后询问的时候二分就好了。然后对于不是整块的修改和询问可以直接改完之后再快排,这样常数小了很多。

  懒得改了,贴sbt的吧。

 

/**************************************************************

    Problem: 3343

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:9976 ms

    Memory:47712 kb

****************************************************************/

 

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

using namespace std ;

#define MAXN 2000100

#define MAXB 1100

#define L( t ) Left[ t ]

#define R( t ) Right[ t ]

#define K( t ) Key[ t ]

#define S( t ) Size[ t ]

#define update( t )S( t )=S(L( t ))+S(R( t ))+1

#define check( ch )( ch >='0'&& ch <='9')

void getint(int&t ){

 int ch ;for( ch =getchar(  );!check( ch ); ch =getchar(  ));

 t = ch -'0';

 for( ch =getchar(  );check( ch ); ch =getchar(  )) t *=10, t += ch -'0';

}

int Left[ MAXN ], Right[ MAXN ], Key[ MAXN ], Size[ MAXN ], V =0;

void left(int&t ){

 int k =R( t );

 R( t )=L( k );update( t );

 L( k )= t ;update( k );

 t = k ;

}

void right(int&t ){

 int k =L( t );

 L( t )=R( k );update( t );

 R( k )= t ;update( k );

 t = k ;

}

void maintain(int&t ){

 if(S(L(L( t )))>S(R( t ))){

     right( t );

     maintain(R( t ));maintain( t );

     return;

 }

 if(S(R(R( t )))>S(L( t ))){

     left( t );

     maintain(L( t ));maintain( t );

     return;

 }

 if(S(R(L( t )))>S(R( t ))){

     left(L( t ));right( t );

     maintain(L( t )),maintain(R( t ));

     maintain( t );

     return;

 }

 if(S(L(R( t )))>S(L( t ))){

     right(R( t ));left( t );

     maintain(L( t )),maintain(R( t ));

     maintain( t );

     return;

 }

}

void Insert(int k ,int&t ){

 if(! t ){

     t =++ V ;

     L( t )=R( t )=0;

     S( t )=1,K( t )= k ;

     return;

 }

 S( t )++;

 Insert( k , k <K( t )?L( t ):R( t ));

 maintain( t );

}

 

void Delete(int k ,int&t ){

 if( k ==K( t )){

     if(!L( t )){

         t =R( t );return;

     }

     if(!R( t )){

         t =L( t );return;

     }

     right( t );Delete( k ,R( t ));

 }else Delete( k , k <K( t )?L( t ):R( t ));

 update( t );

 maintain( t );

}

 

int Rank(int k ,int t ){

 if(! t )return 0;

 if( k <=K( t ))return S(R( t ))+1+Rank( k ,L( t ));

 return Rank( k ,R( t ));

} 

int a[ MAXN ], block[ MAXN ], head[ MAXB ], tail[ MAXB ], roof[ MAXB ], C[ MAXB ];

int n , m , b =0;

int Query(int l ,int r ,int c ){

 if( block[ l ]== block[ r ]){

     int x = block[ l ];

     if( head[ x ]== l && tail[ x ]== r )return Rank( c - C[ x ], roof[ x ]);

     int cnt =0;

     for(int i = l ; i <= r ; i ++)if( a[ i ]>= c - C[ x ]) cnt ++;

     return cnt ;

 }

 int cnt =Query( l , tail[ block[ l ]], c )+Query( head[ block[ r ]], r , c );

 for(int i = block[ l ]+1; i < block[ r ]; i ++){

     cnt +=Rank( c - C[ i ], roof[ i ]);

 }

 return cnt ;

}

 

void Change(int l ,int r ,int c ){

 if( block[ l ]== block[ r ]){

     int x = block[ l ];

     if( l == head[ x ]&& r == tail[ x ]){

         C[ x ]+= c ;

         return;

     }

     for(int i = l ; i <= r ; i ++){

         Delete( a[ i ], roof[ x ]);

         a[ i ]+= c ;

         Insert( a[ i ], roof[ x ]);

     }

     return;

 }

 Change( l , tail[ block[ l ]], c ),Change( head[ block[ r ]], r , c );

 for(int i = block[ l ]+1; i < block[ r ]; i ++){

     C[ i ]+= c ;

 }

}

 

int main(  ){

 memset( roof ,0,sizeof( roof ));

 memset( C ,0,sizeof( C ));

 L(0)=R(0)=S(0)=0;

 getint( n ),getint( m );

 for(int i =0; i ++< n ;)getint( a[ i ]);

 b =int(sqrt( n ));

 for(int i =0; i ++< b ;){

     for(int j =( i -1)* b ; j ++< i * b ;){

         block[ j ]= i ;

         Insert( a[ j ], roof[ i ]);

     }

     head[ i ]=( i -1)* b +1, tail[ i ]= i * b ;

 }

 if( b * b < n ){

     head[ b +1]= b * b +1, tail[ b +1]= n ;

     for(int i = b * b ; i ++< n ;){

         block[ i ]= b +1;

         Insert( a[ i ], roof[ b +1]);

     }

 }

 while( m --){

     int ch , l , r , c ;

     for( ch =getchar(  );!( ch >='A'&& ch <='Z'); ch =getchar(  ));

     if( ch =='M'){

         getint( l ),getint( r ),getint( c );

         Change( l , r , c );

     }else{

         getint( l ),getint( r ),getint( c );

         printf("%d\n",Query( l , r , c ));

     }

 }

 return 0;

}

 

你可能感兴趣的:(ZOJ)