参考:

http://blog.csdn.net/clove_unique/article/details/50630280

gty课件

找一个好的风格太难了,自己习惯用struct,就强行用struct写了一下数组版的,同时加了些宏简化代码

都是迭代写法

splay要维护fa指向父亲

rotate是把x转到fa,要更新f和x

splay是把x转到tar的孩子,x成为root就是tar=0,注意更新root

ins考虑空树,考虑已经存在,插入新节点的话要保留last到最后处理父亲,然后做splay

(递归写法的传引用已经解决了设置祖先的问题)

del

先找要删除的,splay到根

1.多个直接--

2.空树直接root=0

3.只有一个儿子,令独生子变成根,删去该点。
4.左右儿子都有。找到左子树中权值最大的点,将其 splay 到左儿子的位置。然后将 整棵右子树挂在左儿子的右边。删除节点。

其他操作差不多了

ps:比treap慢了一倍

//
// main.cpp
// splay
//
// Created by Candy on 27/11/2016.
// Copyright © 2016 Candy. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
struct node{
int fa,ch[],v,w,size;
}t[N];
int cnt,root;
inline int wh(int x){return t[pa].ch[]==x;}
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline void rotate(int x){//x-->pa
int f=t[x].fa,g=t[f].fa,c=wh(x);
if(g) t[g].ch[wh(f)]=x;
t[f].ch[c]=t[x].ch[c^];t[t[f].ch[c]].fa=f;
t[x].ch[c^]=f;t[f].fa=x;
t[x].fa=g;
update(f);update(x);
}
inline void splay(int x,int tar){//x-->x.fa==tar
for(;t[x].fa!=tar;rotate(x))
if(t[pa].fa!=tar) rotate(wh(x)==wh(pa)?pa:x);
if(tar==) root=x;
} inline int nw(int v){
cnt++;
t[cnt].v=v;t[cnt].ch[]=t[cnt].ch[]=t[cnt].fa=;
t[cnt].w=t[cnt].size=;
return cnt;
}
inline void ins(int v){
if(root==){root=nw(v);return;}//empty tree
int x=root,last=;
while(x!=){
if(t[x].v==v){t[x].w++;t[x].size++;splay(x,);return;}
last=x;
if(v<t[x].v) x=lc; else x=rc;
}
int tmp=nw(v);
if(v<t[last].v) t[last].ch[]=tmp;
else t[last].ch[]=tmp;
t[tmp].fa=last;update(last);//no need for ancient because splay()
splay(tmp,);
}
inline int find(int v){
int x=root;
while(x!=){
if(v==t[x].v) break;
if(v<t[x].v) x=lc;
else x=rc;
}
if(x!=) splay(x,);
return x;
}
inline int pre(){
int x=t[root].ch[];
while(rc) x=rc;
return x;
}
inline void del(int v){
int x=find(v);
if(t[x].w>) {t[x].w--,t[x].size--;return;}
if(lc==&&rc==) root=;
else if(rc==) t[lc].fa=,root=lc;
else if(lc==) t[rc].fa=,root=rc;
else{
int tmp=t[root].ch[];
while(t[tmp].ch[]) tmp=t[tmp].ch[];
splay(tmp,x);
t[tmp].ch[]=rc;t[rc].fa=tmp;
t[tmp].fa=;
root=tmp;
update(root);
}
}
inline int rnk(int v){
int x=root,ls=;
while(x!=){
if(t[x].v==v){
int ans=ls+t[lc].size+;
splay(x,);
return ans;
}
if(v<t[x].v) x=lc;
else ls+=t[lc].size+t[x].w,x=rc;
}
return -;
}
inline int kth(int k){
int x=root,ls=;
while(x!=){
int tmp=ls+t[lc].size;
if(tmp+<=k&&k<=tmp+t[x].w){
splay(x,);return t[x].v;
}
if(k<=tmp) x=lc;
else ls=tmp+t[x].w,x=rc;
}
return -;
}
inline int pre(int v){
int ans=,x=root;
while(x!=){
if(t[x].v<v) ans=x,x=rc;
else x=lc;
}
return ans;
}
inline int suf(int v){
int ans=,x=root;
while(x!=){//printf("suf %d %d\n",x,t[x].v);
if(v<t[x].v) ans=x,x=lc;
else x=rc;
}
return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
n=read();
while(n--){
op=read();x=read();
switch(op){
case :ins(x);break;
case :del(x);break;
case :printf("%d\n",rnk(x));break;
case :printf("%d\n",kth(x));break;
case :ans=pre(x);printf("%d\n",t[ans].v);break;
case :ans=suf(x);printf("%d\n",t[ans].v);break;
}
}
return ;
}

[2016-11-30]

复习了一遍

注意:

find和ins操作要splay,有的地方直接return的话忘记splay了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
struct node{
int fa,ch[],w,size,v;
}t[N];
int cnt,root;
inline void update(int x){t[x].size=t[lc].size+t[rc].size+t[x].w;}
inline int wh(int x){return t[pa].ch[]==x;}
inline void rotate(int x){
int f=t[x].fa,g=t[f].fa,c=wh(x);
if(g) t[g].ch[wh(f)]=x;t[x].fa=g;
t[f].ch[c]=t[x].ch[c^];t[t[f].ch[c]].fa=f;
t[x].ch[c^]=f;t[f].fa=x;
update(f);update(x);
}
inline void splay(int x,int tar){
for(;t[x].fa!=tar;rotate(x))
if(t[pa].fa!=tar) rotate(wh(pa)==wh(x)?pa:x);
if(tar==) root=x;
}
inline int nw(int v){
cnt++;
t[cnt].ch[]=t[cnt].ch[]=t[cnt].fa=;
t[cnt].w=t[cnt].size=;t[cnt].v=v;
return cnt;
}
void ins(int v){
if(root==){root=nw(v);return;}
int x=root,last=;
while(x){
if(t[x].v==v){t[x].w++;t[x].size++;splay(x,);return;}
last=x;
if(v<t[x].v) x=lc;else x=rc;
}
int _=nw(v);
if(v<t[last].v) t[last].ch[]=_;
else t[last].ch[]=_;
t[_].fa=last;
splay(_,);
}
int find(int v){
int x=root;
while(x){
if(t[x].v==v) break;//not return cause splay
if(v<t[x].v) x=lc;else x=rc;
}
if(x!=) splay(x,);
return x;
}
void del(int v){
int x=find(v);
if(t[x].w>){t[x].w--;t[x].size--;return;}
if(lc==&&rc==) root=;
else if(rc==) t[lc].fa=,root=lc;
else if(lc==) t[rc].fa=,root=rc;
else{
int _=lc;
while(t[_].ch[]) _=t[_].ch[];
splay(_,x);
t[_].ch[]=rc;t[rc].fa=_;
t[_].fa=;root=_;
update(root);
}
}
int rnk(int v){
int x=root,ls=;
while(x){
if(t[x].v==v){
int ans=ls+t[lc].size+;
splay(x,);
return ans;
}
if(v<t[x].v) x=lc;else ls+=t[lc].size+t[x].w,x=rc;
}
return -;
}
int kth(int k){
int x=root,ls=;
while(x){
int _=ls+t[lc].size;
if(_<k&&k<=_+t[x].w) return t[x].v;
if(k<=_) x=lc;
else ls=_+t[x].w,x=rc;
}
return -;
}
int pre(int v){
int x=root,ans=;
while(x){
if(v>t[x].v) ans=x,x=rc;
else x=lc;
}
return ans;
}
int suf(int v){
int x=root,ans=;
while(x){
if(v<t[x].v) ans=x,x=lc;
else x=rc;
}
return ans;
}
int n,op,x,ans;
int main(int argc, const char * argv[]){
n=read();
while(n--){
op=read();x=read();
switch(op){
case :ins(x);break;
case :del(x);break;
case :printf("%d\n",rnk(x));break;
case :printf("%d\n",kth(x));break;
case :ans=pre(x);printf("%d\n",t[ans].v);break;
case :ans=suf(x);printf("%d\n",t[ans].v);break;
}
}
return ;
}

[普通平衡树splay]【学习笔记】的更多相关文章

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

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

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

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

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

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

  4. 【洛谷P3369】普通平衡树——Splay学习笔记(一)

    二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...

  5. 【洛谷P3391】文艺平衡树——Splay学习笔记(二)

    题目链接 Splay基础操作 \(Splay\)上的区间翻转 首先,这里的\(Splay\)维护的是一个序列的顺序,每个结点即为序列中的一个数,序列的顺序即为\(Splay\)的中序遍历 那么如何实现 ...

  6. [Splay][学习笔记]

    胡扯 因为先学习的treap,而splay与treap中有许多共性,所以会有很多地方不会讲的很细致.关于treap和平衡树可以参考这篇博客 关于splay splay,又叫伸展树,是一种二叉排序树,它 ...

  7. [Note]Splay学习笔记

    开个坑记录一下学习Splay的历程. Code 感谢rqy巨佬的代码,让我意识到了Splay可以有多短,以及我之前的Splay有多么的丑... int fa[N], ch[N][2], rev[N], ...

  8. splay学习笔记

    伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.(来自百科) 伸展树的操作主要是 –rotate(x) 将x旋转到x的父亲的位置 voi ...

  9. Treap-平衡树学习笔记

    平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...

  10. [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家

    1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...

随机推荐

  1. ReSharper.8.0.14.856注册码

    ReSharper.8.0.14.856注册码 用户名:ronle 注册码:ZoJzmeVBoAv9Sskw76emgksMMFiLn4NM 网络转载

  2. 一个struts2登录bug的解决

    点登录的时候,在url后面总会加上一个;jsessionid=xxx 使找不到页面 的404 Bug ,百思不得其解,最后终于找到解决方案,实验最终成功解决了这个bug,下面是解决方案 1,增加依赖  ...

  3. 自从升级到macOS后,整个人都不好了

    电脑一直莫名的随机卡死,各种软件都出现了一些崩溃和不稳定的情况. Siri就是个笑话,启用后就开始索引本地硬盘,不管你有没有正在工作:直到你启动Siri,会暂停一下,然后就算是你开在哪不动,过两分钟, ...

  4. SqlServer-无限递归树状图结构设计和查询

    在现实生活中,公司的部门设计会涉及到很多子部门,然后子部门下面又存在子部门,形成类似判断的树状结构,比如说评论楼中楼的评论树状图,职位管理的树状图结构等等,实现类似的树状图数据结构是在开发中经常出现的 ...

  5. Javascript:Javascript数据类型详解

    要成为一个优秀的前端工程师,系统的学习Javascript,有夯实的Javascript基础,以及对语言本身的深刻的理解,是基本功.从Javascript数据类型开始,我将对Javascript知识体 ...

  6. [deviceone开发]-do_Http组件示例

    一.简介 详细展示do_Http组件的使用,包括get,post,upload,form,download的http请求.另外还附加了一个Java实现的后台程序作为参考.初学者强烈推荐. 二.效果图 ...

  7. Spring(6)—— AOP

    AOP(Aspect-OrientedProgramming)面向切面编程,与OOP完全不同,使用AOP编程系统被分为切面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...

  8. Linux0.11内核--加载可执行二进制文件之3.exec

    最后剩下最核心的函数do_execve了,由于这里为了简单起见我不分析shell命令的情况, /* * 'do_execve()'函数执行一个新程序. */ //// execve()系统中断调用函数 ...

  9. [转]Android App整体架构设计的思考

    1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...

  10. 【iOS】在Swift中使用JSONModel

    前言 首先所有的Model还是使用oc来写——看到这一句是不是想关网页了- - #,在swift里面直接写一直报错所以就将就用oc来写了,这里主要是分享一下搭配Alamofire使用的经验. 声明 欢 ...