樹堆,在數據結構中也稱Treap,是指有一個隨機附加域滿足堆的性質的二叉搜索樹,其結構相當於以隨機數據插入的二叉搜索樹。其基本操作的期望時間複雜度爲O(logn)。相對於其他的平衡二叉搜索樹,Treap的特點是實現簡單,且能基本實現隨機平衡的結構。
採用結構體存儲節點
struct node
{
int lc,rc;
int pri;//rand();
int key;
int size;
int cnt;//note the repeat
#define lc(x) t[x].lc //left child
#define rc(x) t[x].rc //right child
#define v(x) t[x].key
#define p(x) t[x].pri
#define c(x) t[x].cnt
#define s(x) t[x].size
};
更新函數
inline void update(const int &k)
{
s(k)=s(lc(k))+s(rc(k))+c(k);
return;
}
右旋
inline void Zig(int &k) //right turn;
{
int y=lc(k);
lc(k)=rc(y);
rc(y)=k;
s(y)=s(k);
update(k);
k=y;
return;
}
左旋
inline void Zag(int &k) //left turn;
{
int y=rc(k);
rc(k)=lc(y);
lc(y)=k;
s(y)=s(k);
update(k);
k=y;
return;
}
插入
inline void insert(int &k,const int &key)
{
if(!k) {
k=++pool;
v(k)=key;
p(k)=rand();
c(k)=s(k)=1;
lc(k)=rc(k)=0;
return;
}
else ++s(k);
if(v(k)==key) ++c(k);
else if(key<v(k)) {
insert(lc(k),key);
if(p(lc(k))<p(k)) Zig(k);
}
else {
insert(rc(k),key);
if(p(rc(k))<p(k)) Zag(k);
}
return;
}
刪除
inline void remove(int &k,const int &key)
{
if(v(k)==key) {
if(c(k)>1) --c(k),--s(k);//repeat numbers;
else if(!lc(k)||!rc(k)) k=lc(k)+rc(k); //list node
else if(p(lc(k))<p(rc(k))) Zig(k),remove(k,key);
else Zag(k),remove(k,key);
return;
}
--s(k); //maintenance size;
if(key<v(k)) remove(lc(k),key);
else remove(rc(k),key);
return;
}
求 x 的前趨(前趨定義爲小於 x,且最大的數);
inline int Query_pre(const int &key)
{
int x=root,res=-INF;
while(x) {
if(v(x)<key) res=v(x),x=rc(x); //? <=
else x=lc(x);
}
return res;
}
求 x 的後繼(後繼定義爲大於 x,且最小的數)。
inline int Query_suf(const int &key)
{
int x=root,res=INF;
while(x) {
if(v(x)>key) res=v(x),x=lc(x); //??>=
else x=rc(x);
}
return res;
}
查詢排名爲 x 的數;
inline int Query_kth(int k)
{
int x=root;
while(x) {
if(s(lc(x))<k&&s(lc(x))+c(x)>=k) return v(x);
if(s(lc(x))>=k) x=lc(x);
else k-=s(lc(x))+c(x),x=rc(x);
}
return 0;
}
查詢 x 數的排名(若有多個相同的數,因輸出最小的排名);
inline int Query_rank(const int &key)
{
int x=root,res=0;
while(x) {
if(key==v(x)) return res+s(lc(x))+1;
if(key<v(x)) x=lc(x);
else res+=s(lc(x))+c(x),x=rc(x);
}
return res;
}
完整代碼
//普通平衡樹
#include<bits/stdc++.h>
#define INF 2147483646
using namespace std;
const int N=1e6+5;
struct node
{
int lc,rc;
int pri;//rand();
int key;
int size;
int cnt;//note the repeat
#define lc(x) t[x].lc //left child
#define rc(x) t[x].rc //right child
#define v(x) t[x].key
#define p(x) t[x].pri
#define c(x) t[x].cnt
#define s(x) t[x].size
};
node t[N];
int pool=0;
int root=0;
int n;
inline void update(const int &k)
{
s(k)=s(lc(k))+s(rc(k))+c(k);
return;
}
inline void Zig(int &k) //right turn;
{
int y=lc(k);
lc(k)=rc(y);
rc(y)=k;
s(y)=s(k);
update(k);
k=y;
return;
}
inline void Zag(int &k) //left turn;
{
int y=rc(k);
rc(k)=lc(y);
lc(y)=k;
s(y)=s(k);
update(k);
k=y;
return;
}
inline void insert(int &k,const int &key)
{
if(!k) {
k=++pool;
v(k)=key;
p(k)=rand();
c(k)=s(k)=1;
lc(k)=rc(k)=0;
return;
}
else ++s(k);
if(v(k)==key) ++c(k);
else if(key<v(k)) {
insert(lc(k),key);
if(p(lc(k))<p(k)) Zig(k);
}
else {
insert(rc(k),key);
if(p(rc(k))<p(k)) Zag(k);
}
return;
}
inline void remove(int &k,const int &key)
{
if(v(k)==key) {
if(c(k)>1) --c(k),--s(k);//repeat numbers;
else if(!lc(k)||!rc(k)) k=lc(k)+rc(k); //list node
else if(p(lc(k))<p(rc(k))) Zig(k),remove(k,key);
else Zag(k),remove(k,key);
return;
}
--s(k); //maintenance size;
if(key<v(k)) remove(lc(k),key);
else remove(rc(k),key);
return;
}
inline int Query_pre(const int &key)
{
int x=root,res=-INF;
while(x) {
if(v(x)<key) res=v(x),x=rc(x); //? <=
else x=lc(x);
}
return res;
}
inline int Query_suf(const int &key)
{
int x=root,res=INF;
while(x) {
if(v(x)>key) res=v(x),x=lc(x); //??>=
else x=rc(x);
}
return res;
}
inline int Query_kth(int k)
{
int x=root;
while(x) {
if(s(lc(x))<k&&s(lc(x))+c(x)>=k) return v(x);
if(s(lc(x))>=k) x=lc(x);
else k-=s(lc(x))+c(x),x=rc(x);
}
return 0;
}
inline int Query_rank(const int &key)
{
int x=root,res=0;
while(x) {
if(key==v(x)) return res+s(lc(x))+1;
if(key<v(x)) x=lc(x);
else res+=s(lc(x))+c(x),x=rc(x);
}
return res;
}
/*
1、插入 x 數;
2、刪除 x 數(若有多個相同的數,因只刪除一個);
3、查詢 x 數的排名(若有多個相同的數,因輸出最小的排名);
4、查詢排名爲 x 的數;
5、求 x 的前趨(前趨定義爲小於 x,且最大的數);
6、求 x 的後繼(後繼定義爲大於 x,且最小的數)。
*/
int main()
{
// freopen("1.in","r",stdin);
scanf("%d",&n);
int opt,x;
for(int i=1;i<=n;i++) {
scanf("%d%d",&opt,&x);
switch(opt) {
case 1 : insert(root,x); break;
case 2 : remove(root,x); break;
case 3 : printf("%d\n",Query_rank(x)); break;
case 4 : printf("%d\n",Query_kth(x)); break;
case 5 : printf("%d\n",Query_pre(x)); break;
case 6 : printf("%d\n",Query_suf(x)); break;
}
}
// getchar();
return 0;
}
注:代碼部分來自《一本通提高篇》
有所改動。