• 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
    ",Query( l , r , c ));
         }
     }
     return 0;
    }
  • 相关阅读:
    windows bat脚本检测空白文件
    linux把文件夹作为img镜像给rk3288烧录
    嵌入式非浮点型交叉编译器下载
    嵌入式linux date -s写入保存时间后,开机启动相差八小时
    android5.1编译 collect2: ld terminated with signal 9 [Killed]
    qt5.9.9交叉编译并运行到目标板完整版(无界面版本)
    嵌入式linux编译移植 vsftpd 源码修改
    嵌入式Linux板子date时间和hwclock不一致
    ubuntu14.0输入密码后进不去桌面
    C 语言 指针
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3568114.html
Copyright © 2020-2023  润新知