普通平衡树
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. PERFORMANCE_SCHEMA 详解

    http://keithlan.github.io/2015/07/17/22_performance_schema/ http://www.markleith.co.uk/ http://www.c ...

  2. android之frame动画详解

    上一篇我们说了android中的tween动画,这一篇我们说说frame动画,frame动画主要是实现了一种类似于gif动画的效果,就是多张图按预先设定好的时间依次连续显示. 新建一个android项 ...

  3. 加密算法 DES 3DES RSA AES 简介

    数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为[密文],使其只能在输入相应的[密钥]之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人 ...

  4. 深入理解Javascript变量作用域

    在学习JavaScript的变量作用域之前,我们应当明确几点: a.JavaScript的变量作用域是基于其特有的作用域链的. b.JavaScript没有块级作用域. c.函数中声明的变量在整个函数 ...

  5. C#中堆和栈的区别分析(有待更新总结)

    转载:http://blog.csdn.net/zevin/article/details/5721495 一.预备知识-程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区 ...

  6. android 微信分享没反应问题总结

     一.废话 我必须说我再这个上面吃了很多的亏,所以希望有人不跟我一样吃亏.因为我本身不够仔细的原因,所以我希望能够做一些总结.---废话讲完. 这个文章已经过时了.是几年前写的.http://www. ...

  7. ASP.NET Web API 通过参数控制返回类型(JSON|XML)

    一个很实用的技巧,可以在访问web api服务的时候指定返回数据的格式类型,比如 json 或者 xml. 因为 web api 默认返回的是XML格式,但是现在json 比较流行,同时网上也有其他的 ...

  8. javascript:console.log()是什么js库里的?

    这个不是什么库的,这个是浏览器的函数,如果你使用firefox并且装有firebug插件,当使用console.log(……)时,会把括号内的字符串输出到控制台,当然,在IE中这个是没有的,要报错.相 ...

  9. 关于jQuery $.isNumeric vs. $.isNaN vs. isNaN

    在jQuery中,有几种方式可以判断一个对象是否是数字,或者可否转换为数字. 首先,jQuery.isNaN()在最新版本中已经被移除了(1.7之后),取而代之的是  jQuery.isNumeric ...

  10. html》meta标签笔记

    meta是html语言head区的一个辅助性标签.也许你认为这些代码可有可无.其实如果你能够用好meta标签,会给你带来意想不到的效果,meta标签的作用有:搜索引擎优化(SEO),定义页面使用语言, ...