BZOJ3224: Tyvj 1728 普通平衡树
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
写了Splay、Treap和替罪羊树。然而并不觉得后面两个好写或者比Splay快啊。
Splay:
#include <bits/stdc++.h>
#define N 100010
#define INF 10000010
#define mid ((l+r)>>1)
#define Lc cur->ch[0]
#define Rc cur->ch[1]
#define rep(i,l,r) for (int i=l;i<=r;i++)
using namespace std;
int n;
struct node{
int x,num,size;
node *ch[2],*fa;
}t[N],*root,*tail=t;
template <class Aqua>
inline void read(Aqua &s){
s=0; Aqua f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
while (isdigit(c)) s=s*10+c-'0',c=getchar();
s*=f;
}
inline node *newnode(int x,int d){
node *cur=++tail;
cur->x=x; cur->num=cur->size=d;
cur->ch[0]=cur->ch[1]=cur->fa=t;
return cur;
}
void pre(){
root=newnode(-INF,1);
root->ch[1]=newnode(INF,1);
root->ch[1]->fa=root;
root->size=2;
t->x=t->num=t->size=0;
t->ch[0]=t->ch[1]=t->fa=t;
}
inline node *Min(node *a,node *b){
return (a->x<b->x)?a:b;
}
inline node *Max(node *a,node *b){
return (a->x<b->x)?b:a;
}
inline int get(node *cur){
return (cur->fa->ch[0]==cur)?0:1;
}
inline void update(node *cur){
cur->size=Lc->size+Rc->size+cur->num;
}
void rotate(node *cur){
node *fa=cur->fa; int x=get(cur);
cur->fa=fa->fa; fa->fa->ch[get(fa)]=cur;
fa->fa=cur; fa->ch[x]=cur->ch[x^1];
fa->ch[x]->fa=fa; cur->ch[x^1]=fa;
update(fa),update(cur);
}
void splay(node *cur,node *&to){
for (node *end=to->fa;cur->fa!=end;rotate(cur))
if (cur->fa->fa!=end)
rotate((get(cur)^get(cur->fa))?cur:cur->fa);
to=cur;
}
void insert(int x){
node *fa,*cur;
for (cur=root;cur!=t;cur=(cur->x>x)?Lc:Rc){
cur->size++; fa=cur;
if (cur->x==x){
cur->num++; break;
}
}
if (cur==t){
cur=newnode(x,1); cur->fa=fa;
fa->ch[(x<fa->x)?0:1]=cur;
}
splay(cur,root);
}
node *find(node *cur,int x){
return (cur->x==x)?cur:((cur->x>x)?find(Lc,x):find(Rc,x));
}
int qrank(node *cur){
splay(cur,root);
return Lc->size+1;
}
node *select(node *cur,int k){
return (k<=Lc->size)?select(Lc,k):((k<=Lc->size+cur->num)?cur:select(Rc,k-Lc->size-cur->num));
}
node *pre(node *cur,int x){
return (cur==t)?t+1:((cur->x>=x)?pre(Lc,x):Max(cur,pre(Rc,x)));
}
node *nxt(node *cur,int x){
return (cur==t)?t+2:((cur->x<=x)?nxt(Rc,x):Min(cur,nxt(Lc,x)));
}
int main(){
read(n);
pre();
int opt,x; node *tmp;
rep(i,1,n){
read(opt),read(x);
if (opt==1)
insert(x);
if (opt==2){
tmp=find(root,x);
if (tmp->num!=1)
tmp->num--,splay(tmp,root);
else{
splay(pre(root,x),root);
splay(nxt(root,x),root->ch[1]);
root->ch[1]->ch[0]=t;
update(root->ch[1]),update(root);
}
}
if (opt==3){
printf("%d\n",qrank(tmp=find(root,x))-1);
splay(tmp,root);
}
if (opt==4){
printf("%d\n",(tmp=select(root,x+1))->x);
splay(tmp,root);
}
if (opt==5){
printf("%d\n",(tmp=pre(root,x))->x);
splay(tmp,root);
}
if (opt==6){
printf("%d\n",(tmp=nxt(root,x))->x);
splay(tmp,root);
}
}
return 0;
}
Treap:
#include <bits/stdc++.h>
#define N 100010
#define INF INT_MAX
using namespace std;
int n;
struct tree{
tree *ch[2],*fa;
int p,v,size;
}t[N],*tail=t,*root=t;
template <class Aqua>
inline void read(Aqua &s){
s=0; Aqua f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
while (isdigit(c)) s=s*10+c-'0',c=getchar();
s*=f;
}
inline int getfa(tree *cur){
return (cur->fa->ch[0]==cur?0:1);
}
inline void update(tree *cur){
cur->size=cur->ch[0]->size+cur->ch[1]->size+1;
}
inline void rotate(tree *cur){
int x=getfa(cur); tree *fa=cur->fa;
fa->fa->ch[getfa(fa)]=cur;
cur->fa=fa->fa;
cur->ch[x^1]->fa=fa;
fa->ch[x]=cur->ch[x^1];
fa->fa=cur;
cur->ch[x^1]=fa;
update(fa); update(cur);
}
tree *insert(tree *cur,int d,int p,tree *fa){
if (cur==t){
cur=++tail; cur->size=1;
cur->v=d; cur->p=p;
cur->fa=fa;
cur->ch[0]=cur->ch[1]=t;
fa->ch[d<fa->v?0:1]=cur;
return cur;
}
int x=d<cur->v?0:1;
cur->ch[x]=insert(cur->ch[x],d,p,cur);
if (cur->ch[x]->p<cur->p)
rotate(cur=cur->ch[x]);
update(cur);
return cur;
}
tree *del(tree *cur,int d){
if (cur->v==d){
if (cur->size==1)
return t;
else{
int x=cur->ch[0]->p<=cur->ch[1]->p?0:1;
rotate(cur=cur->ch[x]);
cur->ch[x^1]=del(cur->ch[x^1],d);
update(cur);
return cur;
}
}
int x=d<cur->v?0:1;
cur->ch[x]=del(cur->ch[x],d);
update(cur);
return cur;
}
int getrank(tree *cur,int d){
return (cur==t?1:(cur->v>=d?getrank(cur->ch[0],d):cur->ch[0]->size+1+getrank(cur->ch[1],d)));
}
tree *select(tree *cur,int d){
return (d<=cur->ch[0]->size?select(cur->ch[0],d):(d>cur->ch[0]->size+1?select(cur->ch[1],d-cur->ch[0]->size-1):cur));
}
int main(){
srand(20010823);
read(n);
int op,x;
root=insert(root,-INF,rand(),t);
root=insert(root,INF,rand(),t);
t->size=0; t->p=INF;
for (int i=1;i<=n;i++){
read(op),read(x);
if (op==1)
root=insert(root,x,rand(),t);
if (op==2)
root=del(root,x);
if (op==3)
printf("%d\n",getrank(root,x)-1);
if (op==4)
printf("%d\n",select(root,x+1)->v);
if (op==5)
printf("%d\n",select(root,getrank(root,x)-1)->v);
if (op==6)
printf("%d\n",select(root,getrank(root,x+1))->v);
}
return 0;
}
Scapegoat Tree:
#include <bits/stdc++.h>
#define N 100010
#define INF 2000000010
#define alpha 0.65
using namespace std;
int n,cnt;
struct tree{
tree *fa,*ch[2];
int size,num,x;
}t[N],*q[N],*root=t+1,*node=t,*tail=t+2;
template <class Aqua>
inline void read(Aqua &s){
s=0; Aqua f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; c=getchar();}
while (isdigit(c)) s=s*10+c-'0',c=getchar();
s*=f;
}
void pre(){
root->x=-INF; (t+2)->x=INF;
root->ch[1]=t+2; (t+2)->fa=root;
root->ch[0]=root->fa=(t+2)->ch[0]=(t+2)->ch[1]=t;
(t+2)->size=root->num=(t+2)->num=1; root->size=2;
}
inline tree *newnode(int x){
(++tail)->x=x;
tail->size=tail->num=1;
tail->ch[0]=tail->ch[1]=t;
return tail;
}
inline bool check(tree *cur){
return (max(cur->ch[0]->size,cur->ch[1]->size)>=(double)cur->size*alpha);
}
void ins(tree *cur,int x){
cur->size++;
if (cur->x==x && !cur->num){
cur->num++;
return;
}
int k=(x<cur->x?0:1);
if (cur->ch[k]==t){
cur->ch[k]=newnode(x);
cur->ch[k]->fa=cur;
}
else
ins(cur->ch[k],x);
if (check(cur)) node=cur;
}
void del(tree *cur,int x){
cur->size--;
if (cur->num && cur->ch[0]->size+1==x){
cur->num--;
if (check(cur)) node=cur;
return;
}
if (cur->ch[0]->size+cur->num>=x)
del(cur->ch[0],x);
else
del(cur->ch[1],x-cur->ch[0]->size-cur->num);
if (check(cur)) node=cur;
}
int rank(tree *cur,int x){
return (cur==t?1:(cur->x>=x?rank(cur->ch[0],x):rank(cur->ch[1],x)+cur->ch[0]->size+cur->num));
}
int select(tree *cur,int x){
return (cur->ch[0]->size>=x?select(cur->ch[0],x):(cur->ch[0]->size+cur->num<x?select(cur->ch[1],x-cur->ch[0]->size-cur->num):cur->x));
}
void dfs(tree *cur){
if (cur==t) return;
dfs(cur->ch[0]);
if (cur->num)
q[++cnt]=cur;
dfs(cur->ch[1]);
}
void build(tree *&cur,int l,int r,tree *fa){
if (l>r){
cur=t; return;
}
int mid=l+r>>1;
cur=q[mid];
cur->fa=fa;
build(cur->ch[0],l,mid-1,cur);
build(cur->ch[1],mid+1,r,cur);
cur->size=cur->ch[0]->size+cur->ch[1]->size+1;
}
void rebuild(tree *cur,int x){
cnt=0; dfs(cur);
tree *fa=cur->fa;
build((fa==t?root:(fa->ch[0]==cur?fa->ch[0]:fa->ch[1])),1,cnt,fa);
}
int main(){
read(n);
pre();
int opt,x;
for (int i=1;i<=n;node=t,i++){
read(opt),read(x);
if (opt==1)
ins(root,x);
if (opt==2)
del(root,rank(root,x));
if (opt==3)
printf("%d\n",rank(root,x)-1);
if (opt==4)
printf("%d\n",select(root,x+1));
if (opt==5)
printf("%d\n",select(root,rank(root,x)-1));
if (opt==6)
printf("%d\n",select(root,rank(root,x+1)));
if (node!=t)
rebuild(node,i);
}
return 0;
}

本文介绍了一种名为普通平衡树的数据结构,该结构可以高效地进行插入、删除、查询等操作。文章提供了Splay、Treap和替罪羊树三种实现方式的代码示例,并详细解释了每种方法的特点。
1万+

被折叠的 条评论
为什么被折叠?



