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

FhqTreap的区间翻转的更多相关文章

  1. [BZOJ 3223 & Tyvj 1729]文艺平衡树 & [CodeVS 3243]区间翻转

    题目不说了,就是区间翻转 传送门:BZOJ 3223 和 CodeVS 3243 第一道题中是1~n的区间翻转,而第二道题对于每个1~n还有一个附加值 实际上两道题的思路是一样的,第二题把值对应到位置 ...

  2. codevs3243 区间翻转

    题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N,下一行N个数表示原 ...

  3. WIKIOI 3243 区间翻转

    3243 区间翻转 题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N ...

  4. hdu-3487-Play with Chain-(splay 区间翻转,切割,插入)

    题意: 区间翻转,切割,插入 // File Name: ACM/HDU/3487.cpp // Author: Zlbing // Created Time: 2013年08月10日 星期六 21时 ...

  5. hdu-1890-Robotic Sort splay区间翻转

    题意: 依次找第i大的数下标pos[i],然后将区间[i,pos[i]]翻转 分析: splay树区间翻转 // File Name: ACM/HDU/1890.cpp // Author: Zlbi ...

  6. bzoj3223 Tyvj 1729 文艺平衡树(Splay Tree+区间翻转)

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2202  Solved: 1226[Submit][Sta ...

  7. [置顶] hdu 1890 伸展树区间翻转

    题意: 给你n个数,每次先输出第i大的数的位置(如果有多个,选下标小的那个),然后每次将第i个位置到第i大的数所在位置之间的数进行翻转. 思路:输入的数组可能有多个相同的值,我们可以进行两次排序把数组 ...

  8. hdu3397区间覆盖,区间翻转,区间合并,区间求和

    调了很久的代码..注意区间翻转和覆盖的操作互相的影响 /* 区间替换操作怎么搞? 应该是加个tag标记 如果整个区间都是0|1,那么把若有tag的话直接set1|0即可,也不用设置tag标记 反之要设 ...

  9. CODEVS 4655 序列终结者-splay(区间更新、区间翻转、区间最值)

    4655 序列终结者  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解       题目描述 Description 网上有许多题,就是给定一个序列,要 ...

随机推荐

  1. Html,CSS和盒子

    Html指超文本标记语言(HyperText Markup Language)是一种用于创建网页的标准标记语言. CSS 指层叠样式表 (Cascading Style Sheets),样式定义如何显 ...

  2. 从JS的深拷贝与浅拷贝到jq的$.extend()方法

    一.堆内存与栈内存 堆和栈都是内存中划分出来的用来存储的区域,栈为自动分配的内存空间,它由系统自动释放,堆为动态分配的内存,大小不定也不会自动释放. 二.js基本数据类型与引用类型的不同 基本数据类型 ...

  3. NPOI的基本用法,导出Excel

    void DownloadForAccountIndex(IReadOnlyList<AccountInfoView> list) { NPOI.HSSF.UserModel.HSSFWo ...

  4. jmeter 安装

    3.1 windows10环境下测试工具jmeter安装与配置 3.1.1下载安装java 浏览器中打开链接:http://down-www.7down.net/pcdown/soft/xiazai/ ...

  5. echarts 页面对应更改

    ---legrnd legend: { icon: "circle", orient: 'vertical', right: 10, top: 20, bottom: 20, da ...

  6. 商誉专题RN及H5项目总结

    React(基础框架): React 是基础框架,是一套基础设计实现理念,开发者不能直接使用它来开发移动应用或者网页. React.js(web网页开发):在React框架之上,发展出了React.j ...

  7. 【dp】合唱队形

    题目描述 NN位同学站成一排,音乐老师要请其中的(N-KN−K)位同学出列,使得剩下的KK位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K,他们的身高分别为 ...

  8. 理解vue 修饰符sync

    也是在vux中看到了这个sync 现在我们来看看vue中的sync 我们先看下官方文档:vue .sync 修饰符,里面说vue .sync 修饰符以前存在于vue1.0版本里,但是在在 2.0 中移 ...

  9. 《STL源码剖析》----2.23 value_type()和__type_traits<>如何实现

    在2.13小节destory()第二版本接受两个迭代器找出元素类型,代码如下 其中value_type()判断出类型,__type_traits判断是否存在trivial destructor 在3. ...

  10. Java IO系列之四:NIO通信模型

    分布式rpc框架有很多,比如dubbo,netty,还有很多其他的产品.但他们大部分都是基于nio的, nio是非阻塞的io,那么它的内部机制是怎么实现的呢. 1.由一个专门的线程处理所有IO事件,并 ...