zoukankan      html  css  js  c++  java
  • FhqTreap的区间翻转

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

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

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

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

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

    显然,这样复杂度十分糟糕,甚至达到了暴力都比不上的 (Theta(n imes 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 ;
    }
    
    May you return with a young heart after years of fighting.
  • 相关阅读:
    webdav srs相关
    How To Configure WebDAV Access with Apache on Ubuntu 14.04
    ubuntu 编译lighttpd
    srs编译及推流测试
    Compile pciutils (lspci, setpci) in Windows x86,在 Windows x86 平台下编译 pciutils (lspci, setpci)
    mingw MSYS2 区别
    Qt之美(三):隐式共享
    Qt之美(二):元对象
    Qt之美(一):d指针/p指针详解
    C++的栈空间和堆空间
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/10785292.html
Copyright © 2011-2022 走看看