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. 通过bin-log对mysql进行数据恢复

    mysqlbinlog --database=数据库名 --start-date="2017-06-01 5:00:00"  --stop-date="2017-06-1 ...

  2. Java Web开发环境配置(JDK+Tomcat++IDEA 14)

    对于未接触过java web开发的大家而言,应该和我一样对java web编程开发比较迷茫,通过查一些资料,大致清楚了java web开发环境的一些基本配置,未做过相关编程的人员可以看一看,由于我刚接 ...

  3. js关闭当前窗口,window.close()方法只能是window.open打开的才能执行关闭

    js关闭当前窗口,window.close()方法只能是window.open打开的才能执行关闭. function closeWin() { //open(location, '_self').cl ...

  4. jquery删除表格行

    $(".mingxirmspan").click(function(){ $(this).closest("tr").remove(); })

  5. Kafka 源代码分析之FileMessageSet

    这里主要分析FileMessageSet类 这个类主要是管理log消息的内存对象和文件对象的类.源代码文件在log目录下.这个类被LogSegment类代理调用用来管理分片. 下面是完整代码.代码比较 ...

  6. weblogic 部署问题定位与解决

    weblogic 做为商用中间件在(EJB.jndi 数据源.日志管理.内存管理.资源配置管理...)  是一些开源免费小型容器无法望其项背的. weblogic 最早由 weblogic Inc. ...

  7. Spring MVC 项目搭建 -3- 快速 添加 spring security

    Spring MVC 项目搭建 -3- 快速 添加 spring security 1.添加 spring-sample-security.xml <!-- 简单的安全检验实现 --> & ...

  8. Hibernate错误:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update

    报错:Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execu ...

  9. 网络编程学习笔记(二)基于TCP的Socket编程

    1.Socket:英文意思插座.两个Java应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为一个Socket. 2.Socket通常用来实现client-server(客户端 ...

  10. Unity-Shader-动态阴影(上) 投影的矩阵变换过程

    [旧博客转移 - 2017年1月20日 01:20 ] 前面的话 最近很长时间没写博文了,一是太忙 ( lan ) 了,二是这段时间又领悟了一些东西,脑子里很混乱,不知道从何写起.但感觉不能再拖延下去 ...