您的位置:首页 > 其它

bzoj 3224: Tyvj 1728 普通平衡树

2017-12-19 10:25 549 查看

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 17583 Solved: 7704
[Submit][Status][Discuss]

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]

比较详细的解释

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000000
using namespace std;
int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn];
int sz,root;
void update(int x){
if(x){
size[x]=cnt[x];
if(ch[x][0])size[x]+=size[ch[x][0]];
if(ch[x][1])size[x]+=size[ch[x][1]];
}
}
int get(int x){
return ch[f[x]][1]==x;
}
void rotate(int x){
int old=f[x],oldf=f[f[x]],whi=get(x);
ch[old][whi]=ch[x][whi^1];f[ch[old][whi]]=old;
if(oldf)ch[oldf][ch[oldf][1]==old]=x;f[x]=oldf;
ch[x][whi^1]=old;f[old]=x;
update(x);update(old);
}
void splay(int x){
for(int fa;fa=f[x];rotate(x))
if(f[fa])rotate(get(fa)==get(x)?fa:x);
root=x;
}
void insert(int x){
if(sz==0){
sz++;root=sz;size[root]=cnt[root]=1;
ch[root][0]=ch[root][1]=f[root]=0;key[root]=x;return;
}
int fa=0,now=root;
while(1){
if(key[now]==x){
cnt[now]++;sz++;update(now);update(fa);splay(now);return;
}
fa=now;now=ch[now][key[now]<x];
if(now==0){
sz++;ch[sz][0]=ch[sz][1]=0;key[sz]=x;f[sz]=fa;size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;update(fa);splay(sz);return;
}
}
}
int find(int x){
int now=root,ans=0;
while(1){
if(key[now]>x)now=ch[now][0];
else{
if(ch[now][0])ans+=size[ch[now][0]];
if(key[now]==x){splay(now);return ans+1;}
ans+=cnt[now];now=ch[now][1];
}
}
}
int findx(int x){
int now=root;
while(1){
if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];
else {
int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(tmp>=x)return key[now];
x-=tmp;now=ch[now][1];
}
}
}
int pre(){
int now=ch[root][0];
while(ch[now][1])now=ch[now][1];
return now;
}
int nxt(){
int now=ch[root][1];
while(ch[now][0])now=ch[now][0];
return now;
}
void clear(int x){
cnt[x]=ch[x][0]=ch[x][1]=f[x]=size[x]=key[x]=0;
}
void del(int x){
int where=find(x);
if(cnt[root]>1){cnt[root]--;update(root);return;}
if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}
if(!ch[root][0]){
int oldroot=root;f[ch[root][1]]=0;root=ch[oldroot][1];clear(oldroot);return;
}
if(!ch[root][1]){
int oldroot=root;f[ch[root][0]]=0;root=ch[oldroot][0];clear(oldroot);return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][1]=ch[oldroot][1];f[ch[oldroot][1]]=root;
clear(oldroot);
update(root);
}
int main(){
freopen("Cola.txt","r",stdin);
int n,opt,x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&opt,&x);
switch(opt){
case 1:insert(x);break;
case 2:del(x);break;
case 3:printf("%d\n",find(x));break;
case 4:printf("%d\n",findx(x));break;
case 5:insert(x);printf("%d\n",key[pre()]);del(x);break;
case 6:insert(x);printf("%d\n",key[nxt()]);del(x);break;
}
}
}


比较好看的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000000
using namespace std;
int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn];
int sz,root;
void clear(int x){
ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
}
bool get(int x){
return ch[f[x]][1]==x;
}
void update(int x){
if(x){
size[x]=cnt[x];
if(ch[x][0])size[x]+=size[ch[x][0]];
if(ch[x][1])size[x]+=size[ch[x][1]];
}
}
void rotate(int x){
int old=f[x],oldf=f[f[x]],whichx=get(x);
ch[old][whichx]=ch[x][whichx^1];
f[ch[old][whichx]]=old;
ch[x][whichx^1]=old;f[old]=x;
f[x]=oldf;
if(oldf)ch[oldf][ch[oldf][1]==old]=x;
update(old);update(x);
}
void splay(int x){
for(int fa;fa=f[x];rotate(x))
if(f[fa])rotate((get(x)==get(fa))?fa:x);
root=x;
}
void insert(int x){//插入操作
if(root==0){//树为空
sz++;ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;size[sz]=cnt[sz]=1;key[sz]=x;return;
}
int now=root,fa=0;
while(1){
if(x==key[now]){//找到一个节点与要插入的数字相同
cnt[now]++;update(now);update(fa);splay(now);break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0){
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
int find(int x){//找x的排名
int now=root,ans=0;
while(1){
if(x<key[now])now=ch[now][0];//从左子树中找
else{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(x==key[now]){splay(now);return ans+1;}//要找的元素就在now位置
ans+=cnt[now];//还要向右儿子找
now=ch[now][1];
}
}
}
int findx(int x){//找排名为x的数字
int now=root;
while(1){
if(ch[now][0]&&x<=size[ch[now][0]])now=ch[now][0];//在左子树中
else{
int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=tmp)return key[now];
x-=tmp;now=ch[now][1];
}
}
}
int pre(){//前驱
int now=ch[root][0];
while(ch[now][1])now=ch[now][1];
return now;
}
int nxt(){//后继
int now=ch[root][1];
while(ch[now][0])now=ch[now][0];
return now;
}
void del(int x){
int whatever=find(x);
if(cnt[root]>1){cnt[root]--;update(root);return;}//根节点的权值大于1
if(!ch[root][0]&&!ch[root][1]){clear(root);root=0;return;}//只有一个数字
if(!ch[root][0]){//没有左儿子
int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;
}
else if(!ch[root][1]){//没有右儿子
int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][1]=ch[oldroot][1];
f[ch[oldroot][1]]=root;
clear(oldroot);
update(root);
}
int main(){
freopen("Cola.txt","r",stdin);
int n,opt,x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&opt,&x);
switch(opt){
case 1:insert(x);break;
case 2:del(x);break;
case 3:printf("%d\n",find(x));break;
case 4:printf("%d\n",findx(x));break;
case 5:insert(x);printf("%d\n",key[pre()]);del(x);break;
case 6:insert(x);printf("%d\n",key[nxt()]);del(x);break;
}
}
}


/*
Treap
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node{
int l,r,v,rnd;
int sz,w;//子树的大小  节点上数字的个数
}tr[100010];
int n,size,root,ans;
void update(int k){
tr[k].sz=tr[tr[k].l].sz+tr[tr[k].r].sz+tr[k].w;
}
void lturn(int &k){
int t=tr[k].r;tr[k].r=tr[t].l;tr[t].l=k;
tr[t].sz=tr[k].sz;update(k);k=t;
}
void rturn(int &k){
int t=tr[k].l;tr[k].l=tr[t].r;tr[t].r=k;
tr[t].sz=tr[k].sz;update(k);k=t;
}
void insert(int &k,int x){
if(k==0){
size++;k=size;
tr[k].sz=tr[k].w=1;tr[k].v=x;tr[k].rnd=rand();
return;
}
tr[k].sz++;
if(tr[k].v==x)tr[k].w++;
else if(x>tr[k].v){
insert(tr[k].r,x);
if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);
}
else{
insert(tr[k].l,x);
if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);
}
}
void del(int &k,int x){
if(k==0)return;
if(tr[k].v==x){
if(tr[k].w>1){tr[k].w--;tr[k].sz--;return;}
if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)rturn(k),del(k,x);
else lturn(k),del(k,x);
}
else if(x>tr[k].v){tr[k].sz--;del(tr[k].r,x);}
else{tr[k].sz--;del(tr[k].l,x);}
}
int query_rank(int k,int x){//查找x的排名
if(k==0)return 0;
if(x==tr[k].v)return tr[tr[k].l].sz+1;
if(x>tr[k].v)return tr[tr[k].l].sz+tr[k].w+query_rank(tr[k].r,x);
return query_rank(tr[k].l,x);
}
int query_num(int k,int x){//查找排名为x的数字
if(k==0)return 0;
if(x<=tr[tr[k].l].sz)return query_num(tr[k].l,x);
else if(x>tr[k].w+tr[tr[k].l].sz)return query_num(tr[k].r,x-tr[k].w-tr[tr[k].l].sz);
return tr[k].v;
}
void query_pro(int k,int x){//查找x的前驱
if(k==0)return;
if(tr[k].v<x){ans=k;query_pro(tr[k].r,x);}
else query_pro(tr[k].l,x);
}
void query_sub(int k,int x){
if(k==0)return;
if(tr[k].v>x){ans=k;query_sub(tr[k].l,x);}
else query_sub(tr[k].r,x);
}
int main(){
freopen("Cola.txt","r",stdin);
scanf("%d",&n);
int opt,x;
while(n--){
scanf("%d%d",&opt,&x);
switch(opt){
case 1:insert(root,x);break;
case 2:del(root,x);break;
case 3:printf("%d\n",query_rank(root,x));break;
case 4:printf("%d\n",query_num(root,x));break;
case 5:ans=0;query_pro(root,x);printf("%d\n",tr[ans].v);break;
case 6:ans=0;query_sub(root,x);printf("%d\n",tr[ans].v);break;
}
}
return 0;
}


[b]一篇很棒的学Treap的论文[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: