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

题目: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 ;

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容