题目链接

Splay基础操作

\(Splay\)上的区间翻转

首先,这里的\(Splay\)维护的是一个序列的顺序,每个结点即为序列中的一个数,序列的顺序即为\(Splay\)的中序遍历

那么如何实现区间翻转呢?

对于一次区间翻转操作\(rev(l,r)\),显然先要找到\(l\)和\(r\)在\(Splay\)中的位置

然后把\(l-1\) \(splay\)到根结点,再把\(r+1\) \(splay\)到\(l\)的右儿子的位置

那么区间\([l,r]\)就到了一个子树上,即\(ch[r+1][0]\)

这样就可以翻转了

把序列上的\([l,r]\)翻转即为把\(Splay\)上\([l,r]\)的子树给翻过来

当然不是这么翻。。

没错!是这么翻。。好诡异

我们只需要把整棵子树的所有节点的左右儿子脚滑交换一下就可以了,可以维护一个类似于线段树区间操作的\(tag\)标记

只需要在查找和最后中序遍历时\(push\_down\)就可以了

完整代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std; const int MAXN=100010;
const int INF=0x3f3f3f3f; inline int read(){
int x=0;char c=getchar();
while(c<'0')c=getchar();
while(c>='0')x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x;
} int n,m,root,Size;
int ch[MAXN][2],f[MAXN],size[MAXN],val[MAXN],tag[MAXN]; inline int get_w(int x){
return ch[f[x]][1]==x;
} inline void push_up(int x){
if(x)size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
} inline void rotate(int x){
int fa=f[x],gfa=f[f[x]],ws=get_w(x);
ch[fa][ws]=ch[x][ws^1];f[ch[fa][ws]]=fa;
ch[x][ws^1]=fa;f[fa]=x;f[x]=gfa;
if(gfa)ch[gfa][ch[gfa][1]==fa]=x;
push_up(fa);push_up(x);
} inline void Splay(int x,int goal){
for(int fa;fa=f[x];rotate(x))
if(fa==goal)break;
else if(f[fa]!=goal) rotate(get_w(x)==get_w(fa)?fa:x);
if(goal==0)root=x;
} inline void insert(int x){
if(root==0){
root=++Size;val[Size]=x;
size[Size]=0;return;
}
int now=root,fa=0;
while(now)fa=now,now=ch[now][x>val[now]];
val[++Size]=x;
f[Size]=fa;ch[fa][x>val[fa]]=Size;
size[Size]=1;Splay(Size,0);
} inline void push_down(int p){ //标记下放
if(tag[p]){
swap(ch[p][0],ch[p][1]);
tag[ch[p][0]]^=1;
tag[ch[p][1]]^=1;
tag[p]=0;
}
} inline int find_num(int x){ //找到序列的第x个数的位置
if(!root)return 0;
int now=root;
while(1){
push_down(now);
if(x<=size[ch[now][0]])now=ch[now][0];
else{
int temp=size[ch[now][0]]+1;
if(x<=temp)return now;
else x-=temp,now=ch[now][1];
}
}
} void print(int x){ //输出答案(中序遍历一遍)
if(!x)return;
push_down(x);
print(ch[x][0]);
if(val[x]!=INF&&val[x]!=-INF)
printf("%d ",val[x]);
print(ch[x][1]);
} void reserve(int l,int r){ //翻转区间[l,r]
int x=find_num(l);
int y=find_num(r+2);
Splay(x,0);Splay(y,x);
tag[ch[ch[root][1]][0]]^=1;
} int main(){
n=read();m=read();
insert(-INF);insert(INF); //翻转[1,x]或[x,n]时需要用到0或n
for(int i=1;i<=n;++i)insert(i);
int l,r;
while(m--){
l=read();r=read();
reserve(l,r);
}
print(root);
puts("");
return 0;
}

【洛谷P3391】文艺平衡树——Splay学习笔记(二)的更多相关文章

  1. [洛谷P3391] 文艺平衡树 (Splay模板)

    初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...

  2. 洛谷P3391文艺平衡树(Splay)

    题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...

  3. BZOJ3223/洛谷P3391 - 文艺平衡树

    BZOJ链接 洛谷链接 题意 模板题啦~2 代码 //文艺平衡树 #include <cstdio> #include <algorithm> using namespace ...

  4. BZOJ3224/洛谷P3391 - 普通平衡树(Splay)

    BZOJ链接 洛谷链接 题意简述 模板题啦~ 代码 //普通平衡树(Splay) #include <cstdio> int const N=1e5+10; int rt,ndCnt; i ...

  5. 洛谷 P3391 文艺平衡树

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

  6. 洛谷P3391 文艺平衡树 (Splay模板)

    模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...

  7. 文艺平衡树 Splay 学习笔记(1)

    (这里是Splay基础操作,reserve什么的会在下一篇里面讲) 好久之前就说要学Splay了,结果苟到现在才学习. 可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构. ...

  8. 平衡树splay学习笔记#1

    这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间 后一半的博客地址:[传送门] 前言骚话 为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉 ...

  9. 平衡树splay学习笔记#2

    讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...

随机推荐

  1. MVC通过ViewBag动态生成Html输出到View

    今天再给自己总结一下,关于ViewBag赋值Html格式值,但是在web页显示不正常; 例如,ViewBag.Content = "<p>你好,我现在测试一个东西.</p& ...

  2. 4_PHP流程控制语句_1_条件控制语句

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. PHP流程控制共有3种类型:条件控制结构.循环结构以及程序跳转和终止语句. 4.1 条件控制语句 4.1.1 if ...

  3. ES6--Promise讲解

    相信凡是写过javascript的童鞋也一定都写过回调方法(callback),简单说回调方法就是将一个方法func2作为参数传入另一个方法func1中,当func1执行到某一步或者满足某种条件的时候 ...

  4. C++ primer学习笔记_6_函数---函数定义、参数传递

    1. 习题参考: 6.14 举一个形参应该是引用类型的例子,再举一个形参不能是引用类型的例子. 答: 形参使用引用类型的情况:(1)避免拷贝传递大对象的时候,这里的string对象s:(2)当需要从函 ...

  5. 【RMAN】TSPITR--RMAN表空间基于时间点的自动恢复

    [RMAN]TSPITR--RMAN表空间基于时间点的自动恢复 一.1  BLOG文档结构图 一.2  前言部分 一.2.1  导读 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其 ...

  6. CentOS环境安装python3,pip

    安装python3(编译安装) 1. 下载python安装包到指定目录 cd /usr/local/src 这里的目录如果不存在可以自己建,当然也可以自己放在自己想放的位置,只要等会儿安装的时候能找到 ...

  7. Java 返回字符串中第一个不重复字符的下标 下标从0开始

    比如abcdefgabdef 其中字符c和g不重复,返回c的小标,下标从0开始,那么是2 package com.example.demo; import org.testng.annotations ...

  8. Java输入流

    import java.util.*;  //java为小写public class TEST{ public static void main(String args[]){ Scanner inp ...

  9. X2E车载数据记录仪

            随着智能驾驶及网联技术深入应用,汽车中传输的数据量与日俱增,包括多种总线数据.视频数据.雷达数据.定位数据等等.据悉,高级别智能驾驶汽车中每秒传输的总线数据就达到G比特级别.而从产品开 ...

  10. Tomcat项目内存参数调优

    一.常见的Java内存溢出有以下三种: 1. Java.lang.OutOfMemoryError: Java heap space 即JVM Heap溢出 解释说明:JVM在启动的时候会自动设置JV ...