美文网首页信息学竞赛题解(IO题解)数据结构
BZOJ-3065: 带插入区间K小值(替罪羊树套权值线段树)

BZOJ-3065: 带插入区间K小值(替罪羊树套权值线段树)

作者: AmadeusChan | 来源:发表于2018-10-16 20:48 被阅读0次

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3065

    刚开始想用splay维护,但是死活想不出旋转时维护信息的方法,果断放弃,然后又打算用分块的思想,插入了sqrt(m)个数后再次分治重建树。ORZ了VFK的博客之后才发现,貌似带根号的会TLE,果断放弃。对于这道题,虽然依赖于旋转的平衡树无法达到要求,但是不依赖或者是依赖旋转程度很小(比如treap)的重量平衡树可以满足套上线段树这个要求,所以我选择了相对比较好写的替罪羊树,然后每次询问就在树上找到相应的一组节点,沿着权值线段树走就好啦。。。

    代码:

    b3119313b07eca801dc0e183932397dda0448389.jpg.png
    #include <cstdio>
    
    #include <algorithm>
    
    #include <cstring>
    
    #include <cmath>
    
     
    
    using namespace std ;
    
     
    
    #define MAXN 80010
    
    #define MAXL 70010
    
    #define a 0.80
    
    #define inf 0x7fffffff
    
    #define check( ch ) ( ch >= '0' && ch <= '9' )
    
    #define L( t ) Left[ t ]
    
    #define R( t ) Right[ t ]
    
    #define K( t ) Key[ t ]
    
    #define S( t ) Size[ t ]
    
    #define T( t ) Tree[ t ]
    
     
    
    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' ;
    
    }
    
      
    
    void putint( int t ) {
    
        if ( ! t ) putchar( '0' ) ; else {
    
            int ans[ 20 ] ; ans[ 0 ] = 0 ;
    
            for ( ; t ; t /= 10 ) ans[ ++ ans[ 0 ] ] = t % 10 ;
    
            for ( ; ans[ 0 ] ; ans[ 0 ] -- ) putchar( '0' + ans[ ans[ 0 ] ] ) ;
    
        }
    
        putchar( '\n' ) ;
    
    }
    
     
    
    struct node {
    
        node *left , *right ;
    
        int sum ;
    
        node (  ) {
    
            sum = 0 ;
    
            left = right = NULL ;
    
        }
    
    } *blank = new( node ) ;
    
     
    
    void Add( int l , int r , int k , node* &t) {
    
        if ( t == blank ) t = new( node ) , t -> left = t -> right = blank ;
    
        t -> sum ++ ;
    
        if ( l == r ) return ;
    
        int mid = ( l + r ) >> 1 ;
    
        if ( k <= mid ) Add( l , mid , k , t -> left ) ; else Add( mid + 1 , r , k , t -> right ) ;
    
    }
    
     
    
    void Del( int l , int r , int k , node* &t) {
    
        t -> sum -- ;
    
        if ( l == r ) return ;
    
        int mid = ( l + r ) >> 1 ;
    
        if ( k <= mid ) Del( l , mid , k , t -> left ) ; else Del( mid + 1 , r , k , t -> right ) ;
    
    }
    
     
    
    int Left[ MAXN ] , Right[ MAXN ] , Key[ MAXN ] , Size[ MAXN ] , V = 0 , roof ;
    
    node *Tree[ MAXN ] ;
    
     
    
    int n , m , w[ MAXN ] ;
    
    int dfn[ MAXN ] , Index ;
    
     
    
    void build( int l , int r , int &t ) {
    
        if ( l > r ) {
    
            t = 0 ; return ;
    
        }
    
        int mid = ( l + r ) >> 1 ;
    
        t = dfn[ mid ] ;
    
        T( t ) = blank , S( t ) = r - l + 1 ;
    
        for ( int i = l ; i <= r ; i ++ ) {
    
            Add( 0 , MAXL , K( dfn[ i ] ) , T( t ) ) ;
    
        }
    
        build( l , mid - 1 , L( t ) ) , build( mid + 1 , r , R( t ) ) ;
    
    }
    
     
    
    node *Range[ MAXN ] ;
    
    int P[ MAXN ] , nr , np ;
    
     
    
    void ranging( int l , int r , int t ) {
    
        if ( r < S( L( t ) ) ) ranging( l , r , L( t ) )
    
        ; else if ( l > S( L( t ) ) ) ranging( l - S( L( t ) ) - 1 , r - S( L( t ) ) - 1 , R( t ) )
    
        ; else {
    
            if ( ! l && r == S( t ) - 1 ) Range[ ++ nr ] = T( t )
    
            ; else {
    
                P[ ++ np ] = K( t ) ;
    
                if ( l < S( L( t ) ) ) ranging( l , S( L( t ) ) - 1 , L( t ) ) ;
    
                if ( r > S( L( t ) ) ) ranging( 0 , r - S( L( t ) ) - 1 , R( t ) ) ;
    
            }
    
        }
    
    }
    
     
    
    void getrange( int l , int r ) {
    
        nr = np = 0 ;
    
        ranging( l - 1 , r - 1 , roof ) ;
    
    }
    
     
    
    void dfs( int t ) {
    
        if ( L( t ) ) dfs( L( t ) ) ;
    
        dfn[ ++ Index ] = t ;
    
        if ( R( t ) ) dfs( R( t ) ) ;
    
    }
    
     
    
    void Recycle( node *t ) {
    
        if ( ! t -> sum ) return ;
    
        if ( t -> left ) Recycle( t -> left ) ;
    
        if ( t -> right ) Recycle( t -> right ) ;
    
        delete( t ) ;
    
    }
    
     
    
    void rebuild( int &t ) {
    
        Index = 0 ;
    
        dfs( t ) ;
    
        for ( int i = 0 ; i ++ < Index ; ) Recycle( T( dfn[ i ] ) ) ;
    
        build( 1 , Index , t ) ;
    
    }
    
     
    
    bool Insert( int r , int k , int h , int &t ) {
    
        if ( ! t ) {
    
            t = ++ V ;
    
            S( t ) = 1 , K( t ) = k , L( t ) = R( t ) = 0 , T( t ) = blank ;
    
            Add( 0 , MAXL , k , T( t ) ) ;
    
            return h > log( V ) / log( 1 / a ) ;
    
        }
    
        bool flag ;
    
        if ( r <= S( L( t ) ) ) flag = Insert( r , k , h + 1 , L( t ) )
    
        ; else flag = Insert( r - S( L( t ) ) - 1 , k , h + 1 , R( t ) ) ;
    
        S( t ) = S( L( t ) ) + S( R( t ) ) + 1 ;
    
        Add( 0 , MAXL , k , T( t ) ) ;
    
        if ( flag && ( max( S( L( t ) ) , S( R( t ) ) ) > a * S( t ) ) ) {
    
            rebuild( t ) ;
    
            return false ;
    
        }
    
        return flag ;
    
    }
    
     
    
    int Change( int r , int k , int t ) {
    
        if ( S( L( t ) ) == r ) {
    
            Del( 0 , MAXL , K( t ) , T( t ) ) ;
    
            int v = K( t ) ; K( t ) = k ;
    
            Add( 0 , MAXL , k , T( t ) ) ;
    
            return v ;
    
        }
    
        int v ;
    
        if ( r < S( L( t ) ) ) v = Change( r , k , L( t ) )
    
        ; else v = Change( r - S( L( t ) ) - 1 , k , R( t ) ) ;
    
        Del( 0 , MAXL , v , T( t ) ) ;
    
        Add( 0 , MAXL , k , T( t ) ) ;
    
        return v ;
    
    }
    
     
    
    int Query( int l , int r , int k ) {
    
        k -- ;
    
        getrange( l , r ) ;
    
        int L = 0 , R = MAXL ;
    
        while ( L < R ) {
    
            int mid = ( L + R ) >> 1 , sum = 0 ;
    
            for ( int i = 0 ; i ++ < nr ; ) sum += Range[ i ] -> left -> sum ;
    
            for ( int i = 0 ; i ++ < np ; ) sum += ( P[ i ] >= L && P[ i ] <= mid ) ? 1 : 0 ;
    
            if ( k < sum ) {
    
                for ( int i = 0 ; i ++ < nr ; ) Range[ i ] = Range[ i ] -> left ;
    
                R = mid ;
    
            } else {
    
                k -= sum ;
    
                for ( int i = 0 ; i ++ < nr ; ) Range[ i ] = Range[ i ] -> right ;
    
                L = mid + 1 ;
    
            }
    
        }
    
        return L ;
    
    }
    
     
    
    int main(  ) {
    
        blank -> left = blank -> right = blank ;
    
        getint( n ) ; for ( int i = 0 ; i ++ < n ; ) getint( w[ i ] ) ;
    
        L( 0 ) = R( 0 ) = S( 0 ) = 0 ;
    
        for ( int i = 0 ; i ++ < n ; ) {
    
            dfn[ i ] = ++ V ; K( V ) = w[ i ] ;
    
        }
    
        build( 1 , n , roof ) ;
    
        getint( m ) ;
    
        int last = 0 ;
    
        while ( m -- ) {
    
            int ch ; for ( ch = getchar(  ) ; ! ( ch >= 'A' && ch <= 'Z' ) ; ch = getchar(  ) ) ;
    
            if ( ch == 'Q' ) {
    
                int x , y , k ; getint( x ) , getint( y ) , getint( k ) ;
    
                x ^= last , y ^= last , k ^= last ;
    
                putint( last = Query( x , y , k ) ) ;
    
            } else if ( ch == 'I' ) {
    
                int x , y ; getint( x ) , getint( y ) ;
    
                x ^= last , y ^= last ;
    
                Insert( x - 1 , y , 0 , roof ) ;
    
            } else {
    
                int x , y ; getint( x ) , getint( y ) ;
    
                x ^= last , y ^= last ;
    
                Change( x - 1 , y , roof ) ;
    
            }
    
        }
    
        return 0 ;
    
    }
    

    相关文章

      网友评论

        本文标题:BZOJ-3065: 带插入区间K小值(替罪羊树套权值线段树)

        本文链接:https://www.haomeiwen.com/subject/mkrkzftx.html