Splay这东西神难打……什么都没动板子敲上就直逼200行了,而且非常难记(仿佛是模板长的必然结果)。但是为什么还要学呢?据说是因为它可以实现区间操作。但是自从我得知无旋Treap也能做到这些,默默对比了一下代码长度之后分分钟抛弃Splay啊= =。

和Treap用随机值和左右旋维护平衡不同的,Splay用它的核心操作Splay来维护平衡。所谓的Splay操作可以把任何一个节点旋转到它的一个祖先节点,而旋转分单旋和双旋,双旋需要对比它与父亲是否在各自父亲的同侧。然后每次需要打标记移区间删树之类的,它居然要把目标区间的两端分别移到根和根的儿子……极其麻烦啊这个东西。放几道例题,再体会吧。见到Splay,才知Treap好。

普通平衡树[Tyvj 1728]

时间限制:1 s   内存限制:128 MB

【题目描述】

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

【输入格式】

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

【输出格式】

对于操作3,4,5,6每行输出一个数,表示对应答案

【样例输入】

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

【样例输出】

106465
84185
492737

【提示】

1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int sj=;
int ch[sj][],f[sj],size[sj],cnt[sj],key[sj];
int sz,root;
inline void clear(int x)
{
ch[x][]=ch[x][]=f[x]=size[x]=cnt[x]=key[x]=;
}
inline bool get(int x)
{
return ch[f[x]][]==x;
}
inline void update(int x)
{
if(x)
{
size[x]=cnt[x];
if(ch[x][]) size[x]+=size[ch[x][]];
if(ch[x][]) size[x]+=size[ch[x][]];
}
}
inline void rotate(int x)
{
int old=f[x],oldf=f[old],whichx=get(x);
ch[old][whichx]=ch[x][whichx^];
f[ch[old][whichx]]=old;
ch[x][whichx^]=old;
f[old]=x;
f[x]=oldf;
if(oldf) ch[oldf][ch[oldf][]==old]=x;
update(old);
update(x);
}
inline void splay(int x)
{
for(int fa;fa=f[x];rotate(x))
if(f[fa]) rotate(get(x)==get(fa)?fa:x);
root=x;
}
inline void insert(int x)
{
if(root==)
{
sz++;
ch[sz][]=ch[sz][]=f[sz]=;
root=sz;
size[sz]=cnt[sz]=;
key[sz]=x;
return;
}
int now=root,fa=;
while()
{
if(x==key[now])
{
cnt[now]++;
update(now);
update(fa);
splay(now);
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==)
{
sz++;
ch[sz][]=ch[sz][]=;
f[sz]=fa;
size[sz]=cnt[sz]=;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
inline int find(int x)
{
int now=root,ans=;
while()
{
if(x<key[now]) now=ch[now][];
else
{
ans+=(ch[now][]?size[ch[now][]]:);
if(x==key[now])
{
splay(now);
return ans+;
}
ans+=cnt[now];
now=ch[now][];
}
}
}
inline int findx(int x)
{
int now=root;
while()
{
if(ch[now][]&&x<=size[ch[now][]])
now=ch[now][];
else
{
int temp=(ch[now][]?size[ch[now][]]:)+cnt[now];
if(x<=temp) return key[now];
x-=temp;
now=ch[now][];
}
}
}
inline int pre()
{
int now=ch[root][];
while(ch[now][]) now=ch[now][];
return now;
}
inline int next()
{
int now=ch[root][];
while(ch[now][]) now=ch[now][];
return now;
}
inline void del(int x)
{
int whatever=find(x);
if(cnt[root]>)
{
cnt[root]--;
update(root);
return;
}
if(!ch[root][]&&!ch[root][])
{
clear(root);
root=;
return;
}
if(!ch[root][])
{
int oldroot=root;
root=ch[root][];
f[root]=;
clear(oldroot);
return;
}
else if(!ch[root][])
{
int oldroot=root;
root=ch[root][];
f[root]=;
clear(oldroot);
return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][]=ch[oldroot][];
f[ch[oldroot][]]=root;
clear(oldroot);
update(root);
}
int main()
{
int n,opt,x;
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d%d",&opt,&x);
if(opt==) insert(x);
if(opt==) del(x);
if(opt==) printf("%d\n",find(x));
if(opt==) printf("%d\n",findx(x));
if(opt==)
{
insert(x);
printf("%d\n",key[pre()]);
del(x);
}
if(opt==)
{
insert(x);
printf("%d\n",key[next()]);
del(x);
}
}
return ;
}

Splay数组实现【基本操作】

[HZOI 2016][Tyvj 1729]文艺平衡树

时间限制:1 s   内存限制:128 MB

【题目描述】

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

【输入格式】

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数

接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

【输出格式】

输出一行n个数字,表示原始序列经过m次变换后的结果

【样例输入】

5 3
1 3
1 3
1 4

【样例输出】

4 3 2 1 5

【数据范围】

N,M<=100000

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int siz,sum,flag;
node *ch[],*fa;
void pushdown(node *nd)
{
if(flag)
{
swap(ch[],ch[]);
if(ch[]!=nd) ch[]->flag^=;
if(ch[]!=nd) ch[]->flag^=;
flag=;
}
}
void update()
{
siz=ch[]->siz+ch[]->siz+;
}
}c[],*tail=c,*root,*null;
int n,m,a1,a2;
void init()
{
null=++tail;
null->siz=;
null->ch[]=null->ch[]=null;
null->sum=null->flag=;
}
node* newnode(node *fa)
{
node *nd=++tail;
nd->fa=fa;
nd->siz=;
nd->ch[]=nd->ch[]=null;
nd->flag=;
return nd;
}
void rot(node*& x,int d)
{
node* y=x->fa;
y->ch[!d]=x->ch[d];
if(x->ch[d]!=null) x->ch[d]->fa=y;
x->fa=y->fa;
if(y->fa!=null)
(y==y->fa->ch[])?y->fa->ch[]=x:y->fa->ch[]=x;
x->ch[d]=y;
y->fa=x;
x->update();
y->update();
}
node *build(node *fa,int lf,int rg)
{
if(lf>rg) return null;
node *nd=newnode(fa);
if(lf==rg)
{
nd->sum=lf;
return nd;
}
int mid=(lf+rg)>>;
nd->sum=mid;
nd->ch[]=build(nd,lf,mid-);
nd->ch[]=build(nd,mid+,rg);
nd->update();
return nd;
}
void splay(node *nd,node *tar)
{
while(nd->fa!=tar)
{
node *ne=nd->fa;
if(nd==ne->ch[])
{
if(ne->fa!=tar&&ne==ne->fa->ch[])
rot(ne,);
rot(nd,);
}
else
{
if(ne->fa!=tar&&ne==ne->fa->ch[])
rot(ne,);
rot(nd,);
}
}
if(tar==null) root=nd;
}
node *kth(node *nd,int k)
{
nd->pushdown(null);
if(nd->ch[]->siz+==k) return nd;
if(nd->ch[]->siz+>k) return kth(nd->ch[],k);
else return kth(nd->ch[],k-nd->ch[]->siz-);
}
void rev(int l,int r)
{
node *x=kth(root,l);
node *y=kth(root,r+);
splay(x,null);
splay(y,root);
y->ch[]->flag^=;
}
void dfs(node *nd)
{
if(nd==null) return;
nd->pushdown(null);
dfs(nd->ch[]);
if(nd->sum>=&&nd->sum<=n)
printf("%d ",nd->sum);
dfs(nd->ch[]);
}
int main()
{
scanf("%d%d",&n,&m);
init();
root=build(null,,n+);
for(int i=;i<=m;i++)
{
scanf("%d%d",&a1,&a2);
rev(a1,a2);
}
dfs(root);
return ;
}

Splay指针实现【区间翻转】

SuperMemo
Time Limit:5s    Memory Limit:65536K
Case Time Limit:2s

Description

Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

  1. ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
  2. REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
  3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
  4. INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
  5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
  6. MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2

To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.

Input

The first line contains (≤ 100000).

The following n lines describe the sequence.

Then follows M (≤ 100000), the numbers of operations and queries.

The following M lines describe the operations and queries.

Output

For each "MIN" query, output the correct answer.

Sample Input

5
1
2
3
4
5
2
ADD 2 4 1
MIN 4 5

Sample Output

5

Source

 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ky ch[ch[root][1]][0]
using namespace std;
const int sj=;
const int wq=0x3f3f3f3f;
int n,a[sj],a1,a2,a3,m,rev[sj],mi[sj],add[sj],s[sj];
char ss[];
int pre[sj],ch[sj][],root,tot1,size[sj],key[sj],tot2;
void newnode(int &r,int father,int k)
{
if(tot2) r=s[tot2--];
else r=++tot1;
pre[r]=father;
ch[r][]=ch[r][]=;
key[r]=k;
mi[r]=k;
rev[r]=add[r]=;
size[r]=;
}
void update_rev(int r)
{
if(!r) return;
swap(ch[r][],ch[r][]);
rev[r]^=;
}
void update_add(int r,int d)
{
if(!r) return;
mi[r]+=d;
key[r]+=d;
add[r]+=d;
}
void push_up(int r)
{
size[r]=size[ch[r][]]+size[ch[r][]]+;
mi[r]=min(key[r],min(mi[ch[r][]],mi[ch[r][]]));
}
void push_down(int r)
{
if(rev[r])
{
update_rev(ch[r][]);
update_rev(ch[r][]);
rev[r]=;
}
if(add[r])
{
update_add(ch[r][],add[r]);
update_add(ch[r][],add[r]);
add[r]=;
}
}
void build(int &x,int l,int r,int father)
{
if(l>r) return;
int mid=(l+r)>>;
newnode(x,father,a[mid]);
build(ch[x][],l,mid-,x);
build(ch[x][],mid+,r,x);
push_up(x);
}
void rotate(int x,int kind)
{
int y=pre[x];
push_down(y);
push_down(x);
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(pre[y]) ch[pre[y]][ch[pre[y]][]==y]=x;
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
push_up(y);
}
void splay(int r,int goal)
{
push_down(r);
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal)
{
push_down(pre[r]);
push_down(r);
rotate(r,ch[pre[r]][]==r);
}
else
{
push_down(pre[pre[r]]);
push_down(pre[r]);
push_down(r);
int y=pre[r];
int kind=ch[pre[y]][]==y;
if(ch[y][kind]==r)
{
rotate(r,!kind);
rotate(r,kind);
}
else
{
rotate(y,kind);
rotate(r,kind);
}
}
}
push_up(r);
if(goal==) root=r;
}
int get_kth(int r,int k)
{
push_down(r);
int t=size[ch[r][]]+;
if(t==k) return r;
if(t>k) return get_kth(ch[r][],k);
else return get_kth(ch[r][],k-t);
}
void Add(int x,int y,int d)
{
splay(get_kth(root,x),);
splay(get_kth(root,y+),root);
update_add(ky,d);
push_up(ch[root][]);
push_up(root);
}
void reverse(int x,int y)
{
splay(get_kth(root,x),);
splay(get_kth(root,y+),root);
update_rev(ky);
push_up(ch[root][]);
push_up(root);
}
void revolve(int x,int y,int t)
{
int len=y-x+;
t=(t%len+len)%len;
splay(get_kth(root,y-t+),);
splay(get_kth(root,y+),root);
int tmp=ky;
ky=;
push_up(ch[root][]);
push_up(root);
splay(get_kth(root,x),);
splay(get_kth(root,x+),root);
ky=tmp;
pre[tmp]=ch[root][];
push_up(ch[root][]);
push_up(root);
}
void insert(int x,int p)
{
splay(get_kth(root,x+),);
splay(get_kth(root,x+),root);
newnode(ky,ch[root][],p);
push_up(ch[root][]);
push_up(root);
}
void erase(int r)
{
if(!r) return;
s[++tot2]=r;
erase(ch[r][]);
erase(ch[r][]);
}
void Delete(int x)
{
splay(get_kth(root,x),);
splay(get_kth(root,x+),root);
erase(ky);
pre[ky]=;
ky=;
push_up(ch[root][]);
push_up(root);
}
int Min(int x,int y)
{
splay(get_kth(root,x),);
splay(get_kth(root,y+),root);
return mi[ky];
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++) scanf("%d",&a[i]);
mi[root]=wq;
newnode(root,,-);
newnode(ch[root][],root,-);
build(ky,,n-,ch[root][]);
push_up(ch[root][]);
push_up(root);
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%s%d",ss,&a1);
if(ss[]=='A')
scanf("%d%d",&a2,&a3),Add(a1,a2,a3);
if(ss[]=='R')
{
scanf("%d",&a2);
if(ss[]=='E')
reverse(a1,a2);
if(ss[]=='O')
scanf("%d",&a3),revolve(a1,a2,a3);
}
if(ss[]=='I')
scanf("%d",&a2),insert(a1,a2);
if(ss[]=='D')
Delete(a1);
if(ss[]=='M')
scanf("%d",&a2),printf("%d\n",Min(a1,a2));
}
return ;
}

Splay数组实现【多种区间操作】

为天地立心,为生民请命,为往圣继绝学,为万世开太平。

第二棵树:Splay的更多相关文章

  1. hdu 2871 Memory Control(伸展树splay tree)

    hdu 2871 Memory Control 题意:就是对一个区间的四种操作,NEW x,占据最左边的连续的x个单元,Free x 把x单元所占的连续区间清空 , Get x 把第x次占据的区间输出 ...

  2. 伸展树Splay【非指针版】

    ·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...

  3. 伸展树 Splay Tree

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

  4. 伸展树 Splay 模板

    学习Splay的时候参考了很多不同的资料,然而参考资料太杂的后果就是模板调出来一直都有问题,尤其是最后发现网上找的各种资料均有不同程度的错误. 好在啃了几天之后终于算是啃下来了. Splay也算是平衡 ...

  5. [Splay伸展树]splay树入门级教程

    首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

  6. bzoj 2816: [ZJOI2012]网络 (LCT 建多棵树)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2816 题面: http://www.lydsy.com/JudgeOnline/upload ...

  7. K:伸展树(splay tree)

      伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...

  8. 判断一棵树是否为二叉搜索树(二叉排序树) python

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  9. 【BZOJ4928】第二题 树hash+倍增

    [BZOJ4928]第二题 Description 对于一棵有根树,定义一个点u的k-子树为u的子树中距离u不超过k的部分. 注意,假如u的子树中不存在距离u为k的点,则u的k-子树是不存在的. 定义 ...

随机推荐

  1. SQL Server 2012 酸爽的安装体验

    电脑上已经安装了SQL Server 2008 R2,要想安装SQL Server 2012,必须先将已安装的SQL Server 2008 R2 安全卸载,否则安装过程中会报错! 使用到的卸载软件有 ...

  2. 关于MATLAB处理大数据坐标文件201761

    前几天备战考试,接下来的日子将会继续攻克大数据比赛 虽然停止了一段时间没有提交数据,但是这几天的收获还是有的,对Python 随机森林了解的更了解了 随机森林是由多课决策树组成(当然这个虽然我们初学者 ...

  3. mac下git配置和jenkins打包

    今天自己配置了下jenkins,还算是比较顺利,把整个过程和大家分享下. 1. 查看秘钥是否存在 打开终端查看是否已经存在SSH密钥:cd ~/.ssh 如果没有密钥则不会有此文件夹,有则备份删除, ...

  4. 规定CSS的属性仅在IE下生效 在非IE浏览器下不生效

    css中判断IE版本的语句<!--[if gte IE 6]> Only IE 6/+ <![endif]-->: 1. <!--[if !IE]> 除IE外都可识 ...

  5. Python3.5学习笔记-文件操作

    在Python中,操作文件对象使用open函数来创建,下表列出了常用的操作file的函数: 序号 方法及描述 1.file.close() 关闭文件.关闭后文件不能再进行读写操作. 2.file.fl ...

  6. Servlet启动的时机

    Servlet启动的时机有两个:1.在用户第一次请求时:2.在web应用启动之时. 在web.xml 文件中配置 格式 <servlet> <servlet-name>**** ...

  7. android源码、博文2

      每周精选 第 54 期   精品源码 仿网易新闻app下拉标签选择菜单     仿网易新闻app下拉标签选择菜单,长按拖动排序,点击增删标签控件##示例 https://github.com/we ...

  8. VB6之HTTP服务器的实现(二)

    接上篇,这次做了小小的改动和提升.增加了对POST的支持和对其他方法(GET和POST之外的)选择405回复.另外,增加了对CGI的支持,目前可以使用C语言来写(是不是好蠢的赶脚).相对于上篇,整体做 ...

  9. database.properties数据源

    jdbc.driver_class=oracle.jdbc.driver.OracleDriverjdbc.connection.url=jdbc:oracle:thin:@localhost:152 ...

  10. centos+apache 2.x 开启gzip压缩

    最近做了一个网站(PHP+Apache+MySQL),挂在百度云平台上面,基本配置是2G内存+5Mb带宽,每次打开主页都需要2-3s左右的时间,对于一个垂直搜索引擎来说,用户体验肯定会很差. 于是开始 ...