因为询问比较少,所以我们可以将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 ",Query( l , r , c )); } } return 0; }