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

 

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

 

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

 

 
样例输入 SampleInput [复制数据]
8
1 10
1 20
1 30
3 20
4 2
2 10
5 25
6 -1
 
 
样例输出 SampleOutput [复制数据]
2
20
20
20
 
 
数据范围和注释 Hint
n<=100000 所有数字均在-10^7到10^7内
 
数据结构水题+裸题
第一次敲是splay,有点手生。这种题站一下代码就行了,我用SBT和splay各编了一遍。
 
在这里总结一下splay易错(重要)的几点:
1、如需垃圾回收,放在队列中的必须是指针,这次我拿数组下标存的,发现根本无法回收,觉得太麻烦,就没改了
2、可通过一个nil空节点代替NULL,简便了便捷判断
3、rotate函数调用update()一定要按照调整后的顺序自底向上
4、splay()部分不怎么理解,还要硬背
5、splay()最后注意更新root值
6、所有平衡树都存在的乱转size值的问题,这次问题出现在get_val()中
7、delete()中要单独处理儿子为nil的值
8、delete()注意新root节点的father指针改为nil
9、get_min()判断now==nil情况
10、一些小的马虎错误
 
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
#define MAXT 1000000
#define INF 0x3f3f3f3f
int n,m; struct SBTree
{
int L[MAXT],R[MAXT],K[MAXT],S[MAXT];
queue<int> Q;
int root;
SBTree()
{
root=;
int i;
for (i=;i<MAXT;i++)
{
Q.push(i);
}
}
void update(int &now)
{
S[now]=S[L[now]]+S[R[now]]+;
}
void r_rotate(int &now)
{
int t=L[now];
L[now]=R[t];update(now);
R[t]=now;update(t);
now=t;
}
void l_rotate(int &now)
{
int t=R[now];
R[now]=L[t];update(now);
L[t]=now;update(t);
now=t;
}
void maintain(int &now)
{
if (S[L[L[now]]]>S[R[now]])
{
r_rotate(now);
maintain(L[now]);
maintain(R[now]);
maintain(now);
return;
}
if (S[R[R[now]]]>S[L[now]])
{
l_rotate(now);
maintain(L[now]);
maintain(R[now]);
maintain(now);
return;
}
if (S[L[R[now]]]>S[L[now]])
{
r_rotate(R[now]);
l_rotate(now);
maintain(L[now]);
maintain(R[now]);
maintain(now);
return;
}
if (S[R[L[now]]]>S[R[now]])
{
l_rotate(L[now]);
r_rotate(now);
maintain(L[now]);
maintain(R[now]);
maintain(now);
return;
}
}
void Insert(int &now,int v)
{
if (!now)
{
now=Q.front();
Q.pop();
L[now]=R[now]=;
S[now]=;
K[now]=v;
return ;
}
if (v<=K[now])
{
Insert(L[now],v);
}else
{
Insert(R[now],v);
}
update(now);
maintain(now);
}
void Delete(int &now,int x)
{
// if (!now) throw 1;
if (!now) return ;
if (K[now]==x)
{
if (!L[now]&&!R[now])
{
Q.push(now);
now=;
return ;
}
if (!L[now])
{
Q.push(now);
now=R[now];
return ;
}
if (!R[now])
{
Q.push(now);
now=L[now];
return ;
}
r_rotate(now);
Delete(R[now],x);/**/
update(now);
maintain(now);
return ;
}
if (x<K[now])
{
Delete(L[now],x);
}else
{
Delete(R[now],x);
}
update(now);
maintain(now);
}
int get_val(int &now,int rk)
{
if (rk==S[L[now]]+)
{
return K[now];
}
if (rk<=S[L[now]])
{
return get_val(L[now],rk);
}else
{
return get_val(R[now],rk-S[L[now]]-);
}
}
int get_rank(int &now,int x)
{
if (!now)return INF;
if (x==K[now])
{
return min(S[L[now]]+,get_rank(L[now],x));
}
if (x<K[now])
{
return get_rank(L[now],x);
}else
{
return get_rank(R[now],x)+S[L[now]]+;
}
}
int get_prev(int &now,int v)
{
if (!now)return -INF;
if (K[now]<v)
{
return max(K[now],get_prev(R[now],v));
}else
{
return get_prev(L[now],v);
}
}
int get_next(int &now,int v)
{
if (!now)return INF;
if (K[now]>v)
{
return min(K[now],get_next(L[now],v));
}else
{
return get_next(R[now],v);
}
}
void Scan(int &now)
{
if (!now)return ;
if (S[now]!=S[L[now]]+S[R[now]]+)
{
throw ;
}
Scan(L[now]);
printf("%d ",K[now]);
Scan(R[now]);
}
}SBT;
int main()
{
// freopen("input.txt","r",stdin);
// freopen("output1.txt","w",stdout);
int i,x,opt;
scanf("%d",&m);
for (i=;i<m;i++)
{
scanf("%d%d",&opt,&x);
// cout<<x<<":"<<endl;
switch (opt)
{
case :
SBT.Insert(SBT.root,x);
// SBT.Scan(SBT.root);cout<<endl;
break;
case :
SBT.Delete(SBT.root,x);
// SBT.Scan(SBT.root);cout<<endl;
break;
case :
printf("%d\n",SBT.get_rank(SBT.root,x));
break;
case :
printf("%d\n",SBT.get_val(SBT.root,x));
break;
case :
printf("%d\n",SBT.get_prev(SBT.root,x));
break;
case :
printf("%d\n",SBT.get_next(SBT.root,x));
break;
}
}
return ;
}
 
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
#define MAXT 1000000
#define INF 0x3f3f3f3f
struct node
{
int val,cnt,siz;
node* fa,*ch[];
node(){}
node(int a,int b,int c)
{
val=a;cnt=b;siz=c;
}
void update()
{
siz=ch[]->siz+ch[]->siz+cnt;
}
};
node nil_node(,,),*nil=&nil_node;
struct Splay_tree
{
node *root;
int ncnt;
node E[MAXT];
queue<int> Q;
Splay_tree()
{
root=nil;
ncnt=;
int i;
for (i=;i<MAXT;i++)
{
Q.push(i);
}
}
node* new_node(int key)
{
int now=Q.front();
Q.pop();
E[now].val=key;
E[now].cnt=E[now].siz=;
E[now].ch[]=E[now].ch[]=nil;
return &E[now];
}
void rotate(node *now,int pp)
{
node *y=now->fa;
y->ch[!pp]=now->ch[pp];
if (now->ch[pp]!=nil)now->ch[pp]->fa=y;
now->fa=y->fa;
if (y->fa!=nil)/**/
{
if (y->fa->ch[]==y)
{
y->fa->ch[]=now;
}else
{
y->fa->ch[]=now;
}
}
y->fa=now;
now->ch[pp]=y;
y->update();
now->update();/**/
}
void Splay(node* now,node *top)
{
if (now==top||now==nil)return;
node *y;
while (now->fa!=top)
{
y=now->fa;
if (now==y->ch[])
{
if (y->fa!=top&&y==y->fa->ch[])rotate(now,);
rotate(now,);
}else
{
if (y->fa!=top&&y==y->fa->ch[])rotate(now,);
rotate(now,);
}
}
if (top==nil)
{
root=now;
}
}
void Insert(int key)
{
node* now,*x;
now=root;
if (root==nil)
{
root=new_node(key);
x=root;
root->fa=nil;
return ;
}
while()
{
now->siz++;
if (now->val==key)
{
x=now;/**/
now->cnt++;
break;
}
if (key<now->val)
{
if (now->ch[]==nil)
{
now->ch[]=new_node(key);
now->ch[]->fa=now;
x=now->ch[];
break;
}else
{
now=now->ch[];
continue;
}
}
if (key>now->val)
{
if (now->ch[]==nil)
{
now->ch[]=new_node(key);
now->ch[]->fa=now;
x=now->ch[];
break;
}else
{
now=now->ch[];
continue;
}
}
}
Splay(x,nil);
}
void Delete(node *now)
{
if (now==nil)
{
throw "fuck";
}
if (now->cnt>)
{
now->siz--;
now->cnt--;
while (now!=root)
{
now=now->fa;
now->siz--;
}
return ;
}
Splay(now,nil);
if (now->ch[]==nil)
{
root=now->ch[];
now->ch[]->fa=nil;
return ;
}
if (now->ch[]==nil)
{
root=now->ch[];
now->ch[]->fa=nil;
return ;
}
Splay(get_min(now->ch[]),root);
Splay(get_min(now->ch[]),root);
now->ch[]->ch[]=now->ch[];
now->ch[]->fa=now->ch[];
now->ch[]->fa=nil;
root=now->ch[];
root->update();
}
node* get_min(node* now)
{
if (now==nil)return now;
while (now->ch[]!=nil)now=now->ch[];
return now;
}
node *search(int key)
{
node *now;
now=root;
while ()
{
if (now->val==key)
{
return now;
}
if (key<now->val)
{
now=now->ch[];
}else
{
now=now->ch[];
}
}
return nil;
}
int get_rank(int key)
{
Splay(search(key),nil);
return root->ch[]->siz+;
}
int get_val(node *now,int rank)
{
if (rank<=now->ch[]->siz)
{
return get_val(now->ch[],rank);
}
if (rank>now->ch[]->siz+now->cnt)
{
return get_val(now->ch[],rank-now->ch[]->siz-now->cnt);
}
return now->val;
}
int prev(node *now,int key)
{
int ret=-INF;
if (now==nil)return -INF;
if (key>now->val)
{
return max(prev(now->ch[],key),now->val);
}
if (key<=now->val)
{
return prev(now->ch[],key);
}
}
int next(node *now,int key)
{
if (now==nil)return INF;
if (key<now->val)
{
return min(next(now->ch[],key),now->val);
}
if (key>=now->val)
{
return next(now->ch[],key);
}
}
void Scan(node* now)
{
if (now==nil)
{
return ;
}
if (now->ch[]!=nil && now->ch[]->fa!=now)cout<<"Error_a";
if (now->ch[]!=nil && now->ch[]->fa!=now)cout<< "Error_b";
if (now->siz!=now->ch[]->siz+now->ch[]->siz+now->cnt)cout<<"Error_c";
Scan(now->ch[]);
printf("%d[%d] ",now->val,now->cnt);
Scan(now->ch[]);
}
}spt;
int n,m;
int main()
{
// freopen("input.txt","r",stdin);
// freopen("output1.txt","w",stdout);
int i,x,opt;
scanf("%d",&m);
for (i=;i<m;i++)
{
scanf("%d%d",&opt,&x);
switch (opt)
{
case :
spt.Insert(x);
break;
case :
spt.Delete(spt.search(x));
break;
case :
printf("%d\n",spt.get_rank(x));
break;
case :
printf("%d\n",spt.get_val(spt.root,x));
break;
case :
printf("%d\n",spt.prev(spt.root,x));
break;
case :
printf("%d\n",spt.next(spt.root,x));
break;
}
// spt.Scan(spt.root);cout<<endl;
}
return ;
}
 

tyvj 普通平衡树 SBT or splay的更多相关文章

  1. 三大平衡树(Treap + Splay + SBT)总结+模板[转]

    Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...

  2. 平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

    平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是 ...

  3. 三大平衡树(Treap + Splay + SBT)总结+模板[转]

    Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...

  4. 三大平衡树(Treap + Splay + SBT)总结+模板

    Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...

  5. bzoj3224: Tyvj 1728 普通平衡树(打个splay暖暖手)

    (其实今天好热啊? 题目大意:插入,删除,k小,前驱后继,数的排名. splay和treap裸题...过几天补个treap的 splay: #include<iostream> #incl ...

  6. bzoj3223 文艺平衡树 (treap or splay分裂+合并)

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3313  Solved: 1883 [Submit][S ...

  7. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

  8. 【模板】平衡树——Treap和Splay

    二叉搜索树($BST$):一棵带权二叉树,满足左子树的权值均小于根节点的权值,右子树的权值均大于根节点的权值.且左右子树也分别是二叉搜索树.(如下) $BST$的作用:维护一个有序数列,支持插入$x$ ...

  9. 平衡树模板【splay的实现】

    [平衡树splay实现] 无注释代码 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=1e ...

随机推荐

  1. UIImage载入图片的几种方式及差别

    用UIImage载入图像的方法非常多.最经常使用的是几种:  1.使用imageNamed函数载入: <span style="font-size:14px;">[UI ...

  2. careercup-栈与队列 3.2

    3.2 请设计一个栈,除pop与push方法,还支持min方法,可返回栈元素中的最小值.push.pop和min三个方法的时间复杂度必须为O(1). 我们假设除了用一个栈s1来保存数据,还用另一个栈s ...

  3. labview 移位寄存器、隧道、索引隧道的区别

    Lab view区别:移位寄存器.隧道.索引隧道 最近研究Lab view的时候发现移位寄存器和隧道的功能非常相似但是又有区别 外部数据进入循环体是通过隧道进入的,有几种方式: 图1:For 循环结构 ...

  4. lua 基本

    Lua 的语法比较简单,学习起来也比较省力,但功能却并不弱. 所以,我只简单的归纳一下 Lua 的一些语法规则,使用起来方便好查就可以了.估计看完了,就懂得怎么写 Lua 程序了. 在 Lua 中,一 ...

  5. Apache CXF 3.0: CDI 1.1 Support as Alternative to Spring--reference

    With Apache CXF 3.0 just being released a couple of weeks ago, the project makes yet another importa ...

  6. Spring/Hibernate Improved SQL Logging with log4jdbc---reference

    Hibernate provides SQL logging out of the box, but such logging only shows prepared statements, and ...

  7. Android 上使用 iconfont 的一种便捷方案

    最近在学习 AIOSO(Alibaba Internal Open Source Organization,即阿里巴巴内部开源组织) 的一个子项目MMCherryUI,这是一个流式布局,可以在运行时做 ...

  8. RedHat7配置Nginx实现多域名虚拟主机的SSL/TLS认证(实现单IP以不同证书服务于不同域名)

    以RedHat7(64bit)平台为例 如果RedHat源没法用,可以使用EPEL源 # rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-rel ...

  9. js基础知识之_入门变量和运算符

    js页面效果学习 (轮播图,文字滚动效果等等) javascript能来做什么 1.数据验证 2.将动态的内容写入网页中(ajax) 3.可以对时间做出响应 4.可以读写html中的内容 5.可以检测 ...

  10. sqlserver2005唯一性约束

    [转载]http://blog.163.com/rihui_7/blog/static/21228514320136193392749/ 1.设置字段为主键就是一种唯一性约束的方法,如   int p ...