【洛谷P3391】文艺平衡树——Splay学习笔记(二)
题目链接
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学习笔记(二)的更多相关文章
- [洛谷P3391] 文艺平衡树 (Splay模板)
		
初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...
 - 洛谷P3391文艺平衡树(Splay)
		
题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...
 - BZOJ3223/洛谷P3391 - 文艺平衡树
		
BZOJ链接 洛谷链接 题意 模板题啦~2 代码 //文艺平衡树 #include <cstdio> #include <algorithm> using namespace ...
 - BZOJ3224/洛谷P3391 - 普通平衡树(Splay)
		
BZOJ链接 洛谷链接 题意简述 模板题啦~ 代码 //普通平衡树(Splay) #include <cstdio> int const N=1e5+10; int rt,ndCnt; i ...
 - 洛谷 P3391 文艺平衡树
		
题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 --b ...
 - 洛谷P3391 文艺平衡树 (Splay模板)
		
模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...
 - 文艺平衡树 Splay 学习笔记(1)
		
(这里是Splay基础操作,reserve什么的会在下一篇里面讲) 好久之前就说要学Splay了,结果苟到现在才学习. 可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构. ...
 - 平衡树splay学习笔记#1
		
这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间 后一半的博客地址:[传送门] 前言骚话 为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉 ...
 - 平衡树splay学习笔记#2
		
讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...
 
随机推荐
- c#中关于Convert.ToDouble的一个注意事项
			
今天在写代码的时候被一个小细节坑了,以前没注意,现在才发现,代码如下: private void btnChangeCartonID_Click(object sender, EventArgs e) ...
 - WPS生成多级编号
			
需求: 目前标题是标题1,想要 string 是二级标题,并且编号是 2.1 方案: (1)设置string是二级标题 (2)设置多级编号 选中,右击,选择[项目符号和编号] 选择[多级编号],点击[ ...
 - 2.NET Core设定数据库种子
			
1.使用以下代码在 Models 文件夹中创建一个名为 SeedData 的新类: using Microsoft.EntityFrameworkCore;using Microsoft.Extens ...
 - .NET Core的SqlSugar上手使用小例子
			
开始直接建个空的WEB项目-建Controllers文件夹-开启MVC-添加NuGet程序包SqlSugarCore public class Startup { // This method get ...
 - MVC视图中 TextBoxFor 数据格式化
			
@Html.TextBoxFor(m => m.Birthday,"{0:yyyy-MM-dd}", new { @class = "m-wrap small&qu ...
 - [golang]svg图片默认按照左上角旋转,改为按中心旋转,重新计算中心偏移量
			
1 前言 svg图片默认按照左上角旋转,改为按中心旋转,重新计算中心偏移量 2 代码 type Point struct { X float64 Y float64 } func GetOffsetX ...
 - Java调用Http/Https接口(2)--HttpURLConnection/HttpsURLConnection调用Http/Https接口
			
HttpURLConnection是JDK自身提供的网络类,不需要引入额外的jar包.文中所使用到的软件版本:Java 1.8.0_191. 1.服务端 参见Java调用Http接口(1)--编写服务 ...
 - shell编程必须要掌握的命令-xargs
			
一,说xargs命令前,说一下什么是shell编程 什么是shell编程呢,说白了就是按一定的规则把各种命令组织起来,完成一定的事情.纯属个人理解,哈哈.不管是交互式的shell,还是非交互的shel ...
 - Ajax实现异步请求
			
基本步骤:创建XMLHttpRequest对象-->配置发送参数-->执行发送-->处理响应 ajax 通俗讲有四个步骤 1.创建Ajax对象2.链接到服务器3.发送请求4.接受返回 ...
 - 解决java依赖poi导出Excel表时,没有出现下载提示的问题
			
转自:https://blog.csdn.net/jinchunzhao123/article/details/88626077 浏览器响应: 而且进入断点调试,所有的数据都执行了就是没有下载提示.而 ...