ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

FhqTreap的区间翻转

2019-04-28 17:40:08  阅读:220  来源: 互联网

标签:rt return int FhqTreap son Treap 区间 NULL 翻转


学 Fhq 就是为了尽量不去写某毒瘤数据结构,所以自然要来杠一杠某数据结构的经典操作:区间反转

听起来玄乎,但只需要一个小 trick 就行了:把原来的区间以下标作为权值建成 Treap , 这样整棵 Treap 的中序遍历就是原区间.

按照这种方法建树,是进行区间操作的第一步.接下来我们考虑如何去在 \Theta ( \log_2^{n}) 的时间内完成这件事.

一个基本的思路是将区间 Split 为 [1,l-1],[l,r],[r+1,n] 三部分,对中间的 [l,r] 进行反转

反转的具体操作是从根到叶子把每个节点的左右儿子互换

显然,这样复杂度十分糟糕,甚至达到了暴力都比不上的 \Theta ( n \times \log_2^{n} )

所以,我们必须考虑去减少我们的操作次数.

这里我们借鉴一下之前学习线段树时的 trick : lazytag (我不信你都学平衡树了还不会线段树)

聪明的你应该已经想到了,对没错,就是通过打 lazytag 来减少我们的操作,想必原理也不用赘述

(这里有个小细节,最后输出前,别忘了把所有的 tag 全部下传到底)

那么什么时候去下传 tag 呢 ? 聪明的你肯定也已经想到了,对,就是在 merge 和 Split 两个函数中,优先下传 tag

建树的时候,其实应该是以使用笛卡尔树的方式建树为佳,但我太懒了,就直接 insert 了

Code :

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define siz(rt) ( rt == NULL ? 0 : rt->size )
#define Drt pair < Treap * , Treap * >

using std::pair ;

const int N = 1e5 + 5 ;

int n , m ;

struct Treap {
    Treap * son[2] ;
    int val , size , rank ;
    bool tag ;
    Treap (int val) : val ( val ) { size = 1 ; rank = rand () ; son[0] = son[1] = NULL ; tag = false ; }
    inline void maintain () {
        this->size = 1 ;
        if ( this->son[0] != NULL ) this->size += this->son[0]->size ;
        if ( this->son[1] != NULL ) this->size += this->son[1]->size ;
        return ;
    }
} * root = NULL ;

inline void pushdown ( Treap * rt ) {
    std::swap ( rt->son[0] , rt->son[1] ) ;
    if ( rt->son[0] != NULL ) rt->son[0]->tag ^= rt->tag ;
    if ( rt->son[1] != NULL ) rt->son[1]->tag ^= rt->tag ;
    rt->tag = false ; return ;
}

inline Drt Split ( Treap * rt , int k ) {
    if ( rt == NULL ) return Drt ( NULL , NULL ) ;
    if ( rt->tag ) pushdown ( rt ) ; Drt t ;
    if ( k <= siz ( rt->son[0] ) ) {
        t = Split ( rt->son[0] , k ) ; rt->son[0] = t.second ;
        rt->maintain () ; t.second = rt ;
    } else {
        t = Split ( rt->son[1] , k - siz ( rt->son[0] ) - 1 ) ;
        rt->son[1] = t.first ; rt->maintain () ; t.first = rt ;
    }
    return t ;
}

inline Treap * merge ( Treap * x , Treap * y ) {
    if ( x == NULL ) return y ; if ( y == NULL ) return x ;
    if ( x->rank < y->rank ) {
        if ( x->tag ) pushdown ( x ) ;
        x->son[1] = merge ( x->son[1] , y ) ;
        x->maintain () ; return x ;
    } else {
        if ( y->tag ) pushdown ( y ) ;
        y->son[0] = merge ( x , y->son[0] ) ;
        y->maintain () ; return y ;
    }
}

inline int Getrank ( Treap * rt , int key ) {
    if ( rt == NULL ) return 0 ;
    if ( key <= rt->val ) return Getrank ( rt->son[0] , key ) ;
    else return Getrank ( rt->son[1] , key ) + siz ( rt->son[0] ) + 1 ;
}

inline int Getkth ( Treap * & rt , int key ) {
    Drt x = Split ( rt , key - 1 ) ;
    Drt y = Split ( x.second , 1 ) ;
    Treap * node = y.first ;
    rt = merge ( x.first , merge ( node , y.second ) ) ;
    return node == NULL ? 0 : node->val ;
}

inline void insert ( Treap * & rt , int key ) {
    int k = Getrank ( rt , key ) ; Drt t = Split ( rt , k ) ;
    Treap * node = new Treap ( key ) ;
    rt = merge ( t.first , merge ( node , t.second ) ) ;
    return ;
}

inline void remove ( Treap * & rt , int key ) {
    int k = Getrank ( rt , key ) ; Drt x = Split ( rt , k - 1 ) ;
    Drt y = Split ( x.second , 1 ) ; delete y.first ;
    rt = merge ( x.first , y.second ) ; return ;
}

inline void reverse ( Treap * & rt , int l , int r ) {
    Drt x = Split ( rt , l - 1 ) ;
    Drt y = Split ( x.second , r - l + 1 ) ;
    y.first->tag = true ;
    rt = merge ( x.first , merge ( y.first , y.second ) ) ;
    return ;
}

inline void print ( Treap * rt ) {
    if ( rt == NULL ) return ;
    if ( rt->tag ) pushdown ( rt ) ;
    print ( rt->son[0] ) ;
    printf ("%d " , rt->val ) ;
    print ( rt->son[1] ) ;
}

int main () {
    srand ( time ( NULL ) ) ;
    scanf ("%d%d" , & n , & m ) ;
    for (int i = 1 ; i <= n ; ++ i) insert ( root , i ) ;
    while ( m -- ) {
        register int l , r ;
        scanf ("%d%d" , & l , & r ) ;
        reverse ( root , l , r ) ;
    }
    print ( root ) ; system ("pause") ; return 0 ;
}

标签:rt,return,int,FhqTreap,son,Treap,区间,NULL,翻转
来源: https://www.cnblogs.com/Equinox-Flower/p/10785292.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有