传送门:>Here<

解法分析

  用splay来维护这个序列。

  一直没有搞明白的是,这里的splay的节点究竟维护的是什么?是权值吗?肯定不是,因为区间是会翻转的,如果维护权值的话很快平衡树就不再满足性质。

  然而从头到尾,唯一始终统一的就是位置——始终是1~n. 因此考虑用节点来维护位置。

  这样在维护splay的时候,翻转一段区间就相当于修改了这一段区间的位置,使原来小的现在大了,原来大的现在小了。放在树上形象的看,就是原来作为父节点的左儿子的统统称为了右儿子。反之亦然。因此只要找出连续的那一段区间,并且翻转左右子树即可。注意为了减少操作次数,可以打懒标记。

  如何找出连续的那一段目标区间?由于要翻转的是区间$[l, r]$,我们可以找到位置(注意,这里的位置也就是平衡树维护的权值的排名了,因此位置i也就是排名第i的)l-1和r+1的点,分别旋转到根节点和根节点的右子树上。这样,根节点的右子节点的左子树就是这段区间了。(想一想,为什么)。特殊的,当边界到达1或n时会溢出,因此我们加入哨兵节点-1和n+1。这样位置i就是排名i+1了。

  值得注意的是何时下传懒标记——根据懒标记的优良传统,不用就不翻转。那唯一要用的时候就是询问位置的时候了,因此只要find的时候下传就可以了。另外翻转两次相当于不翻转,所以用xor1会很方便。

  

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) +(x << ) + c - '', c = getchar();
return x * w;
}
int n,m,L,R;
struct Splay{
int ch[MAXN][],size[MAXN],val[MAXN],fa[MAXN],tag[MAXN],num_node,root;
inline bool Son(int f, int x){
return ch[f][]==x;
}
inline void Update(int x){
size[x] = size[ch[x][]] + size[ch[x][]] + ;
}
inline void Rotate(int x){
int f = fa[x], gf = fa[f];
bool p = Son(f, x), q = !p;
ch[f][p] = ch[x][q];
fa[ch[x][q]] = f;
ch[x][q] = f;
fa[f] = x;
fa[x] = gf;
if(gf != ){
ch[gf][Son(gf,f)] = x;
}else{
root = x;
}
Update(x), Update(f);
}
inline void splay(int x, int target){
while(fa[x] != target){
int f = fa[x], gf = fa[f];
if(gf == target){
Rotate(x);
return;
}
if(Son(gf,f) == Son(f,x)){
Rotate(f), Rotate(x);
}
else{
Rotate(x), Rotate(x);
}
}
}
inline void Insert(int v){
if(root == ){
++num_node;
root = num_node;
size[num_node] = ;
val[num_node] = v;
return;
}
for(int x = root; x != ; x = ch[x][v >= val[x]]){
bool b = v >= val[x];
if(ch[x][b] == ){
++num_node;
ch[x][b] = num_node;
size[num_node] = ;
val[num_node] = v;
fa[ch[x][b]] = x;
splay(ch[x][b], );
}
}
}
inline void Pushdown(int x){
if(x == ) return;
if(!tag[x]) return;
int tmp = ch[x][];
ch[x][] = ch[x][];
ch[x][] = tmp;
tag[x] = ;
tag[ch[x][]] ^= ;
tag[ch[x][]] ^= ;
}
inline int Find(int _k){
int x = root;
for(; x != ;){
Pushdown(x);
if(size[ch[x][]] + == _k){
return x;
}
if(size[ch[x][]] >= _k){
x = ch[x][];
}
else{
_k -= size[ch[x][]] + ;
x = ch[x][];
}
}
}
inline void Reverse(int L, int R){
if(L >= R) return;
splay(Find(L), );
splay(Find(R), root);
tag[ch[ch[root][]][]] ^= ;
}
inline void DEBUG(){
for(int i = ; i <= n; ++i){
printf("%d-->%d lson:%d rson:%d\n",i,val[i],ch[i][],ch[i][]);
}
}
}qxz;
int main(){
// freopen(".in","r",stdin);
n=r, m=r;
qxz.Insert(-);
qxz.Insert(n+);
for(int i = ; i <= n; ++i){
qxz.Insert(i);
}
// qxz.DEBUG();
for(int i = ; i <= m; ++i){
L=r, R=r;
qxz.Reverse(L,R+);
}
for(int i = ; i <= n; ++i){
printf("%d ", qxz.val[qxz.Find(i+)]);
}
return ;
}

「Splay」区间翻转的更多相关文章

  1. 「NOI2016」区间 解题报告

    「NOI2016」区间 最近思维好僵硬啊... 一上来就觉得先把区间拆成两个端点进行差分,然后扫描位置序列,在每个位置维护答案,用数据结构维护当前位置的区间序列,但是不会维护. 于是想研究性质,想到为 ...

  2. 「SDOI2005」区间

    「SDOI2005」区间 传送门 记录每一个位置作为左端点和右端点的出现次数,然后直接考虑差分即可. 参考代码: #include <cstdio> #define rg register ...

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

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

  4. BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题

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

  5. 【模板】文艺平衡树(Splay) 区间翻转 BZOJ 3223

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 N,M<= ...

  6. splay(1区间翻转区间最值与区间修改)

    bzoj1251权限题 题目点这里,你懂得 直接上板子,这个要好好体会 操作是最经典的. #include <algorithm> #include <iostream> #i ...

  7. hdu1890 splay维护区间翻转

    这题的建模有点不太一样,是按结点横坐标赋予键值的 同时每次rotate和splay时都要注意下往上往下更新 /* 先建立好splay tree,将结点按num/输入顺序排序,遍历时每次将当前结点提到根 ...

  8. 「Splay」普通平衡树模板

    口诀: $rotate$:先上再下,最后自己 $splay$:祖父未到旋两次,三点一线旋父亲,三点折线旋自己. $delete$:没有儿子就删光.单个儿子删自己.两个儿子找前驱. 易错点: $rota ...

  9. LOJ#2086. 「NOI2016」区间

    $n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...

随机推荐

  1. 《React Native 精解与实战》书籍连载「React Native 中的生命周期」

    此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...

  2. prometheus排错

    1.导入grafana模板后node-export某些图像无法获取到data: 解决:导入grafana 模板是需要看node-export 版本是否与模板要求的一致,不同版本的node-export ...

  3. ORM 多表操作查询及增删改查

    ------------------------------------------只有对前途乐观的人,才能不怕黑暗,才能有力量去创造光明.乐观不是目的,而是人生旅途中的一种态度. 多表操作 创建模型 ...

  4. H5 60-浮动元素排序规则

    60-浮动元素排序规则 <!DOCTYPE html><html lang="en"><head> <meta charset=" ...

  5. Redis服务端的搭建(初级)

    前方低能,仅适合入门级菜鸟阅读,大神大牛通通闪开! 前言:redis经常被用来做缓存(原因自行科普),基于学习的需要自己搭建了一个redis服务器,考虑到项目的分布式部署,所以前期开始的时候,redi ...

  6. 【学亮IT手记】jQuery each()函数用法实例

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  7. js对字符串的一些操作方法

    1.charCodeAt(index); 返回一个整数,代表下标位置上字符的Unicode的编码. 2.fromCharCode(code1,code2,code3,...); code1代表Unic ...

  8. linux audit审计(8)--ausearch搜索audit日志文件

    ausearch这个工具,可以针对指定的事件来搜索audit日志文件.默认情况下,ausearch搜索/var/log/audit/audit.log这个文件. The ausearch utilit ...

  9. Chrome & QR Code Reader

    Chrome & QR Code Reader Allows to generate a QR Code for the current page and scan a QR Code usi ...

  10. python数学第二天【泰勒展开式】

    1. 泰勒展开式 推论1: 泰勒展开式的应用 推论2: 推论3: