FhqTreap的区间翻转

news/2024/11/21 1:33:09/

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

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


http://www.ppmy.cn/news/610840.html

相关文章

ThinkPHP 详细介绍

ThinkPHP 是一个免费开源的&#xff0c;快速、简单的面向对象的 轻量级PHP开发框架 &#xff0c;创立于2006年初&#xff0c;遵循Apache2开源协议发布&#xff0c;是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则&#xff0c;…

Vitis-AI集成

Vitis-AI集成 Vitis-AI是Xilinx的开发堆栈&#xff0c;用于在Xilinx平台&#xff08;包括边端设备和Alveo卡&#xff09;上进行硬件加速的AI推理。它由优化的IP&#xff0c;工具&#xff0c;库&#xff0c;模型和示例设计组成。设计时考虑到了高效率和易用性&#xff0c;充分发…

Android 设置横屏,竖屏或者禁止横屏的方法

在android 的配置文件AndroidManifest.xml中有 android:screenOrientation属性 下面看下各个属性 "unspecified":默认值 由系统来推断显示方向.判定的策略是和设备相关的&#xff0c;所以不同的设备会有不同的显示方向."landscape":横屏显示&#xff08…

利用C语言控制Exynos4412芯片及硬件 6.27

1.LED 1.需求&#xff1a;点亮LED4 2.看原理图&#xff0c;确定硬件原理&#xff0c;确定管脚XvVSYNC_LDI 给高电平--输出1--灯亮GPIO&#xff1a;通用输入输出端口 GPF3_4 输出高电平--灯亮GP端口 F组号 3.芯片手册GPF3CON&#xff1a;0x114001E0 [19:16] 0x1 OutputGPF3DA…

浅谈MySQL中utf8和utf8mb4的区别

一、什么是UTF8MB4&#xff1f; 我们在使用PhpMyAdmin管理面板时&#xff0c;可以在首页看到名为“Server connection collation”&#xff08;服务器连接排序规则&#xff09;的选项&#xff0c;用来选择所使用的字符集。对于我们常用的UTF8&#xff0c;却有utf8和utf8mb4两种…

洛谷P4053 [JSOI2007]建筑抢修

放题解 题目传送门 放代码 #include <bits/stdc.h>//万能头 #define MAXN 150000//最多的建筑数量&#xff08;数据范围&#xff09; using namespace std;inline int read()//快读 {int ret0,f1;char chgetchar();while (ch<0||ch>9){if (ch-) f-f;chgetchar();}w…

TVM Reduction降低算力

TVM Reduction降低算力 这是有关如何降低算力TVM的介绍材料。像sum / max / min这样的关联约简运算符是线性代数运算的典型构造块。 本文将演示如何降低TVM算力。 from future import absolute_import, print_function import tvm import tvm.testing from tvm import te impo…

Android VideoView播放视频

假如你这个播放视频很简单的一个播放功能&#xff0c;没有其他的特殊要求&#xff0c;那么VideoView播放肯定是最好的选择&#xff0c;当然别人封装好的 使用也是很不错的选择 下面先写一个简单的网络播放 首先在配置文件中&#xff0c;添加联网的权限 <uses-permission…