题目传送门

  转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处

  

经典引文

空间效率:O(n)
时间效率:O(log n)插入、查找、删除
创造者:Daniel Sleator 和 Robert Tarjan

优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根。

Tree Rotation

 
树的旋转是splay的基础,对于二叉查找树来说,树的旋转不破坏查找树的结构。
 

Splaying

 
Splaying是Splay Tree中的基本操作,为了让被查询的条目更接近树根,Splay Tree使用了树的旋转操作,同时保证二叉排序树的性质不变。
Splaying的操作受以下三种因素影响:
  • 节点x是父节点p的左孩子还是右孩子
  • 节点p是不是根节点,如果不是
  • 节点p是父节点g的左孩子还是右孩子
同时有三种基本操作:
 

Zig Step


当p为根节点时,进行zip step操作。
当x是p的左孩子时,对x右旋;
当x是p的右孩子时,对x左旋。
 

Zig-Zig Step

当p不是根节点,且x和p同为左孩子或右孩子时进行Zig-Zig操作。
当x和p同为左孩子时,依次将p和x右旋;
当x和p同为右孩子时,依次将p和x左旋。
 
 

Zig-Zag Step

当p不是根节点,且x和p不同为左孩子或右孩子时,进行Zig-Zag操作。
当p为左孩子,x为右孩子时,将x左旋后再右旋。
当p为右孩子,x为左孩子时,将x右旋后再左旋。
 
 

应用

 
Splay Tree可以方便的解决一些区间问题,根据不同形状二叉树中序遍历结果不变的特性,可以将区间按顺序建二叉查找树。
每次自下而上的一套splay都可以将x移动到根节点的位置,利用这个特性,可以方便的利用Lazy的思想进行区间操作。
对于每个节点记录size,代表子树中节点的数目,这样就可以很方便地查找区间中的第k小或第k大元素。
对于一段要处理的区间[x, y],首先splay x-1到root,再splay y+1到root的右孩子,这时root的右孩子的左孩子对应子树就是整个区间。
这样,大部分区间问题都可以很方便的解决,操作同样也适用于一个或多个条目的添加或删除,和区间的移动。

最后附上自己写的洛谷的模板题的代码: 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+;
int n,m,root,tot;
struct Node{
int ch[],size;
int fa,mark,val;
void add(int x,int y){
ch[]=ch[]=mark=;
val=x;fa=y;size=;}
}t[N];
inline int read()
{
char ch=getchar();int num=;bool flag=false;
while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
return flag?-num:num;
}
inline void pushup(int x)
{
int l=t[x].ch[],r=t[x].ch[];
t[x].size=t[l].size+t[r].size+;
}
inline void pushdown(int x)
{
if(t[x].mark){
t[t[x].ch[]].mark^=;
t[t[x].ch[]].mark^=;
swap(t[x].ch[],t[x].ch[]);
t[x].mark=;}
}
inline void rotate(int x)
{
int y=t[x].fa;
int z=t[y].fa;
int k=(t[y].ch[]==x);
t[z].ch[t[z].ch[]==y]=x;
t[x].fa=z;
t[t[x].ch[k^]].fa=y;
t[y].ch[k]=t[x].ch[k^];
t[x].ch[k^]=y;
t[y].fa=x;
pushup(y);pushup(x);
}
inline void splay(int x,int tag)
{
while(t[x].fa!=tag){
int y=t[x].fa;
int z=t[y].fa;
if(z!=tag)
(t[y].ch[]==x)^(t[z].ch[]==y)?
rotate(x):rotate(y);
rotate(x);
}
if(tag==)root=x;
}
inline void insert(int x)
{
int now=root,fa=;
while(now)
fa=now,now=t[now].ch[x>t[now].val];
now=++tot;
if(fa)t[fa].ch[x>t[fa].val]=now;
t[now].add(x,fa);
splay(now,);
}
inline int find(int x)
{
int now=root;
while(){
pushdown(now);
if(t[t[now].ch[]].size>=x)now=t[now].ch[];
else if(t[t[now].ch[]].size+==x)return now;
else x-=(t[t[now].ch[]].size+),now=t[now].ch[];
}
}
inline void work(int l,int r)
{
l=find(l);r=find(r+);
splay(l,);splay(r,l);
t[t[t[root].ch[]].ch[]].mark^=;
}
inline void print(int x)
{
pushdown(x);
if(t[x].ch[])print(t[x].ch[]);
if(t[x].val>&&t[x].val<n+)
printf("%d ",t[x].val-);
if(t[x].ch[])print(t[x].ch[]);
}
int main()
{
n=read();m=read();
for(int i=;i<=n+;i++)
insert(i);
for(int i=;i<=m;i++){
int l=read();int r=read();
work(l,r);}
print(root);
return ;
}

洛谷P3391文艺平衡树(Splay)的更多相关文章

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

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

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

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

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

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

  4. 洛谷 P3391 文艺平衡树

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

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

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

  6. 洛谷.3391.文艺平衡树(fhq Traep)

    题目链接 //注意反转时先分裂r,因为l,r是针对整棵树的排名 #include<cstdio> #include<cctype> #include<algorithm& ...

  7. 洛谷 P3391 【模板】文艺平衡树(Splay)

    题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...

  8. 【阶梯报告】洛谷P3391【模板】文艺平衡树 splay

    [阶梯报告]洛谷P3391[模板]文艺平衡树 splay 题目链接在这里[链接](https://www.luogu.org/problemnew/show/P3391)最近在学习splay,终于做对 ...

  9. [luogu P3391] 文艺平衡树

    [luogu P3391] 文艺平衡树 题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区 ...

随机推荐

  1. ZooKeeper内部构件

    引言 这个文档包含关于ZK内部工作的信息.目前为止,它讨论了这些主题: 原子广播 日志 原子传播 ZK的核心是一个原子的通信系统,它使所有的服务端保持同步. 保证.属性和定义 通过使用ZooKeepe ...

  2. 【Android】完善Android学习(五:API 3.2)

    备注:之前Android入门学习的书籍使用的是杨丰盛的<Android应用开发揭秘>,这本书是基于Android 2.2API的,目前Android已经到4.4了,更新了很多的API,也增 ...

  3. [洛谷P2365] 任务安排

    洛谷题目链接:任务安排 题目描述 N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时 ...

  4. Spring Boot 启动报错:LoggingFailureAnalysisReporter

    17:57:19: Executing task 'bootRun'... Parallel execution with configuration on demand is an incubati ...

  5. 省队集训 Day3 吴清华

    [题目大意] 给网格图,共有$n * n$个关键节点,横向.纵向距离均为$d$,那么网格总长度和宽度均为$(n+1) * d + 1$,最外围一圈除了四角是终止节点.要求每个关键节点都要通过线连向终止 ...

  6. 【BZOJ】1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名

    [题意]给定n头牛和m对大小关系,求最坏情况下至少还需要比较几对奶牛的大小(在未确定顺序的奶牛对中随机比较) [算法]floyd求传递闭包 [题解]可达说明大小已知,则不可达点对数量就是最少比较次数. ...

  7. MySQL 表和库删不掉,并且表也打不开,不能导出的情况

    linux上的mysql中,最近遇到表和库删不掉,并且表也打不开,不能导出的情况. 在删除数据库时,出现以下错误: ERROR 1010 (HY000): Error dropping databas ...

  8. eclipse+EGIT+GitHub

    下载EGIT:http://wiki.eclipse.org/EGit/FAQ#Where_can_I_find_older_releases_of_EGit.3F 1.下载eclipse版本对应的E ...

  9. perl6中函数参数(1)

    sub F($number is copy){ $number++; say $number; } F(); #下面是错误的 sub F($number){ $number++; say $numbe ...

  10. redis基础之开机自启动和监听(二)

    redis安装好后,每次手动启动很不方便,配置开机自启动. 方法一:设置启动命令到/etc/rc.d/rc.local rc.local文件是系统全局脚本文件,会在其他开机进程脚本文件执行完毕后执行该 ...