[普通平衡树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.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...
随机推荐
- Oracle函数-DECODE
DECODE翻译为解码或译码,因为它可以把查询结果翻译成令用户容易理解的内容. 语法: expr: 表达式 search:搜索值 result:结果值 default:默认值 DECODE函数的第一个 ...
- XAF视频教程来啦,已出7课
XAF交流学习群内的兄弟录制了视频,他没有博客,委拖我发至博客园,希望能让更多的开发人员受益.快速开发企业级应用的好工具! XAF入门01快速浏览 XAF入门02特点. XAF入门03 ...
- SSH(Struts2+Spring+Hibernate)框架搭建流程<注解的方式创建Bean>
此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblo ...
- Python_实现三级目录展示
要求: 1.三级菜单 2.可依次选择进入各子菜单,选择序号进入目录 3.输入b返回上级目录,q退出更改目录 代码实现: #!/bin/env python #!--*--coding:utf-8 -- ...
- ahjesus web动态icon
刚刚逛插件无意间发现的,记录下,里面有demo可以直接run了看效果 http://nicolasbize.com/faviconx/ http://www.miaofree.com/
- Spring声明事务管理
首先我们先了解事务,什么是事务? 简单来说就是要么全部成功,要么什么都不做. 为什么要使用事务? 比如说常用银行系统的例子,如果没有用事务,有人在存入钱的时候出了问题,那么银行系统数据库的数据没有改变 ...
- react引用antd的form表单
引用form是第三方插件ant插件,官网网址:https://ant.design/.用到的antd的版本是@2.0.1.form(https://ant.design/components/form ...
- CSS布局基础——BFC
what's BFC? 第一次看到这个名词,我是拒绝的,css什么时候还有这个东西?于是迫不及待的google了一下,才发现原来它无时无刻不在我们的css当中,只不过它并不是一个属性,不需要我们平常使 ...
- php每天一题:怎么在不使用第三个变量的情况下交换两个变量的值
$a = 'php'; $b = 'my'; list($a,$b) = array($b,$a); echo $a,$b; 很简单,大家试一下是不是交换了!
- xp系统下硬盘安装centos6.5
引言: 电脑系统是Windows XP,电脑没有光驱.手头没有U盘.没有移动硬盘.电脑主板不支持U盘启动,在这种情况下想安装CentOS 6.0,有木有办法? 答案:有办法,请看下面教程! 必备工具: ...