博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
FhqTreap的区间翻转
阅读量:4640 次
发布时间:2019-06-09

本文共 3969 字,大约阅读时间需要 13 分钟。

学 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 
#include
#include
#include
#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 ;}

转载于:https://www.cnblogs.com/Equinox-Flower/p/10785292.html

你可能感兴趣的文章
Symfony2学习笔记之事件分配器
查看>>
Xstream序列化实体
查看>>
F#新Bug,小心! module 里的泛型变量。
查看>>
2017.5.22 git
查看>>
[转载]网站分析的最基本度量(7)——Impression,Click和CTR
查看>>
信号调理-电平调整
查看>>
delphi 使用自定义HANDLE处理消息
查看>>
ASP.NET中的常用快捷键
查看>>
poj 3034 动态规划
查看>>
联合体
查看>>
字符串常见操作
查看>>
kotlin泛型类型变异
查看>>
新博客..第一天..
查看>>
T-SQL 关闭数据库所有连接
查看>>
nIce 不看会后悔的o!
查看>>
多区域显示(6)-版面布局
查看>>
[P4886] 快递员
查看>>
[Winodows Phone 7控件详解]Silverlight toolkit for Windows Phone 7.1控件-7
查看>>
[LeetCode] Maximum Length of Repeated Subarray 最长的重复子数组
查看>>
Cocos2d-x打包安卓apk
查看>>