普通平衡树
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. Android将Activity打成jar包供第三方调用(解决资源文件不能打包的问题)

    转载地址:http://blog.csdn.net/xiaanming/article/details/9257853 最近有一个需要,我们公司做了一个apk客户端,然后其他的公司可以根据自己的需要来 ...

  2. [TypeScript] Configuring TypeScript Which Files to Compile with "Files" and "OutDir"

    This lesson shows how to configure the .tsconfig so you only compile the .ts files you want. It then ...

  3. LeetCode刷题笔录Add Binary

    Given two binary strings, return their sum (also a binary string). For example, a = "11" b ...

  4. mysql其他函数

    mysql,,); +---------------+ ,,) | +---------------+ | +---------------+ row in set (0.22 sec) mysql) ...

  5. hadoop错误FATAL org.apache.hadoop.hdfs.server.namenode.NameNode Exception in namenode join java.io.IOException There appears to be a gap in the edit log

    错误: FATAL org.apache.hadoop.hdfs.server.namenode.NameNode Exception in namenode join java.io.IOExcep ...

  6. Ⅰ.AngularJS的点点滴滴--引导

    AngularJS已经被很多人像炒冷饭一样炒过啦,大部分都是直接复制官方文档没有说明一些注意事项,不过什么都要从头开始吧 页面引导实例化 1.自动实例化 <html> <script ...

  7. 还原或删除sql server 2008数据库时,经常烩出现: “因为数据库正在使用,所以无法获得对数据库的独占访问权”,终解决方案

    还原或删除sql server 2008数据库时,经常烩出现: “因为数据库正在使用,所以无法获得对数据库的独占访问权”,终解决方案如下 关键SQL语句: ALTER DATABASE [dateba ...

  8. MVC Ajax 提交是防止SCRF攻击

    //在View中 <script type="text/javascript"> @functions{ public string ToKenHeaderValue( ...

  9. TCP/IP 协议理解

    TCP/IP 协议(Transmission Control Protocol / internet Protocol),因特网互联协议,又名网络通讯协议.通俗而言:TCP负责发现传输的问题,一有问题 ...

  10. java的集合框架之一

    java是一套很成熟的东西,很多商用的东西都喜欢用它,用的人多,稳定.不过一般也不怎么说起它,因为太常见了,私下里说,写java应用层得就像农民工,每一处都是搭积木,根据设计师的东西如何优雅地搭好积木 ...