[普通平衡树splay]【学习笔记】
参考:
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]【学习笔记】的更多相关文章
- 平衡树splay学习笔记#2
讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...
- 平衡树splay学习笔记#1
这一篇博客只讲splay的前一部分的操作(rotate和splay),后面的一段博客咕咕一段时间 后一半的博客地址:[传送门] 前言骚话 为了学lct我也是拼了,看了十几篇博客,学了将近有一周,才A掉 ...
- 文艺平衡树 Splay 学习笔记(1)
(这里是Splay基础操作,reserve什么的会在下一篇里面讲) 好久之前就说要学Splay了,结果苟到现在才学习. 可能是最近良心发现自己实在太弱了,听数学又听不懂只好多学点不要脑子的数据结构. ...
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 【洛谷P3391】文艺平衡树——Splay学习笔记(二)
题目链接 Splay基础操作 \(Splay\)上的区间翻转 首先,这里的\(Splay\)维护的是一个序列的顺序,每个结点即为序列中的一个数,序列的顺序即为\(Splay\)的中序遍历 那么如何实现 ...
- [Splay][学习笔记]
胡扯 因为先学习的treap,而splay与treap中有许多共性,所以会有很多地方不会讲的很细致.关于treap和平衡树可以参考这篇博客 关于splay splay,又叫伸展树,是一种二叉排序树,它 ...
- [Note]Splay学习笔记
开个坑记录一下学习Splay的历程. Code 感谢rqy巨佬的代码,让我意识到了Splay可以有多短,以及我之前的Splay有多么的丑... int fa[N], ch[N][2], rev[N], ...
- splay学习笔记
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.(来自百科) 伸展树的操作主要是 –rotate(x) 将x旋转到x的父亲的位置 voi ...
- Treap-平衡树学习笔记
平衡树-Treap学习笔记 最近刚学了Treap 发现这种数据结构真的是--妙啊妙啊~~ 咳咳.... 所以发一发博客,也是为了加深蒟蒻自己的理解 顺便帮助一下各位小伙伴们 切入正题 Treap的结构 ...
- [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家
1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...
随机推荐
- 关于大数据企业信息查询的API该怎么写
最近在看API相关的案例,做的是.net开发的工作 对API开发这块很是迷茫,不知道从哪入手,园子里面的朋友有没有研究这块的给点建议 公司目前准备做一款企业数据查询的网站,让我负责API接口这块,基于 ...
- nginx配置多个虚拟主机vhost
在nginx下配置虚拟主机vhost非常方便.主要在nginx的配置文件nginx.conf中添加一个server即可 比如我想配置两个虚拟主机,通过域名linux.com和linux2.com访问, ...
- python基础之数据类型(二)
Python3 元组 Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 不可变的tupl ...
- javascript中的prototype(原型)认识
prototype实现了对象与对象的继承,在JS中变量,函数,几乎一切都是对象,而对象又有_ptoro_属性,这个属性就是通常说的原型,是用来指向这个对象的prototype对象,prototype对 ...
- Easyui的渲染
锻炼完身体九点到电脑旁,加上整理明天的接口文档,到现在22:38:10:-_-!!,心累 今天整理下Easyui是如何渲染的: <input class="easyui-combobo ...
- 十二种获取Spring的上下文环境ApplicationContext的方法
转载:https://my.oschina.net/u/2391658/blog/729414
- js基础知识梳理(最简版)
基础的JavaScript知识,只放XMind截图.小白 JS01 JS02 JS03 最基础的js知识--!
- JQ中的方法、事件及动画
css( ) 除了可以为元素添加样式外,还可用来查询元素,某样式值alert($('.cls1').css('width')); //100px(返回带单位的值)注意:原生CSS样式中有-的去掉并且将 ...
- Java线程
线程 线程 线程(Thread)是控制线程(Thread of Control)的缩写,是程序运行的基本单位,它是具有一定顺序的指令序列(即所编写的程序代码).存放方法中定义局部变量的栈和一些共享数据 ...
- 天津政府应急系统之GIS一张图(arcgis api for flex)讲解(十)态势标绘模块
config.xml文件的配置如下: <widget label="态势标绘" icon="assets/images/impact_area_over.png&q ...