HYSBZ-3224:Tyvj 1728 普通平衡树(splay结构体,无插入求前驱后继)
2017-09-06 09:41
597 查看
3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 15555 Solved: 6769
[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
101 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
10646584185
492737
HINT
1.n的数据范围:n<=1000002.每个数的数据范围:[-2e9,2e9]
思路:splay基本操作。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct SPLAY
{
int val;
int num,size;
int f,l,r;
}a[200000];
int root,size;
void show(int k) //额。。。调试用的
{
if(k==-1)return;
printf("a[%d] father=%d val=%d num=%d size=%d l=%d r=%d\n",k,a[k].f,a[k].val,a[k].num,a[k].size,a[k].l,a[k].r);
show(a[k].l);
show(a[k].r);
}
void maintain(int k)//更新数据
{
if(k==-1)return;
a[k].size=a[k].num;
if(a[k].l!=-1)a[k].size+=a[a[k].l].size;
if(a[k].r!=-1)a[k].size+=a[a[k].r].size;
}
void right_rotate(int k)//右旋
{
int p=a[k].f;
a[k].f=a[p].f;
if(a[p].f!=-1)
{
if(a[a[p].f].l==p)a[a[p].f].l=k;
else a[a[p].f].r=k;
}
else root=k;
a[p].l=a[k].r;
if(a[k].r!=-1)a[a[k].r].f=p;
a[k].r=p;
a[p].f=k;
maintain(p);//旋转后更新数据,顺序不能反
maintain(k);
}
void left_rotate(int k)//左旋
{
int p=a[k].f;
a[k].f=a[p].f;
if(a[p].f!=-1)
{
if(a[a[p].f].l==p)a[a[p].f].l=k;
else a[a[p].f].r=k;
}
else root=k;
a[p].r=a[k].l;
if(a[k].l!=-1)a[a[k].l].f=p;
a[k].l=p;
a[p].f=k;
maintain(p);
maintain(k);
}
void splay(long long k,long long f)
{
while(a[k].f!=f)
{
long long p=a[k].f;
if(a[p].f==f)
{
if(a[p].l==k)right_rotate(k);
else left_rotate(k);
}
else
{
long long ff=a[p].f;
if(p==a[ff].l&&k==a[p].l)right_rotate(p),right_rotate(k);
if(p==a[ff].l&&k==a[p].r)left_rotate(k),right_rotate(k);
if(p==a[ff].r&&k==a[p].r)left_rotate(p),left_rotate(k);
if(p==a[ff].r&&k==a[p].l)right_rotate(k),left_rotate(k);
}
}
}
void insert(int k,int val)//插入
{
if(k<0) //第一次插入root=-1
{
a[size].val=val;
a[size].l=a[size].r=-1;
a[size].f=-1;
a[size].size=a[size].num=1;
root=size;
splay(size,-1);
size++;
return;
}
if(val<a[k].val)
{
if(a[k].l!=-1)insert(a[k].l,val);
else
{
a[size].val=val;
a[size].size=a[size].num=1;
a[size].l=a[size].r=-1;
a[size].f=k;
a[k].l=size;
splay(size,-1);
size++;
}
}
else if(val>a[k].val)
{
if(a[k].r!=-1)insert(a[k].r,val);
else
{
a[size].val=val;
a[size].size=a[size].num=1;
a[size].l=a[size].r=-1;
a[size].f=k;
a[k].r=size;
splay(size,-1);
size++;
}
}
else a[k].num++,a[k].size++,splay(k,-1);//碰到相同的数
maintain(k);
}
int search(int k,int x)//查询x的排名
{
if(a[k].val>x)
{
if(a[k].l!=-1)return search(a[k].l,x);
}
else if(a[k].val<x)
{
if(a[k].r!=-1)return search(a[k].r,x);
}
else
{
splay(k,-1);//先把它旋转到根节点
maintain(k);
return a[k].size-a[k].num+1-(a[k].r==-1?0:a[a[k].r].size);
//取最小排名,去掉重复的数和右边比它大的数
//(早上精神状态不怎么好,这里忘记处理细节,WA了好几发。。)
}
}
int ask(int x)//查找第x小的数
{
int k=root;
while(1)
{
if(a[k].l!=-1&&x<=a[a[k].l].size)k=a[k].l;
else
{
int temp=(a[k].l==-1?0:a[a[k].l].size)+a[k].num;
if(x<=temp)return a[k].val;
x-=temp;
k=a[k].r;
}
}
}
int askpre(int k,int val) //求前驱
{
if(a[k].val>val)
{
if(a[k].l==-1)
{
long long p=a[k].f;
while(p!=-1&&k==a[p].l)k=p,p=a[p].f;
return p;
}
return askpre(a[k].l,val);
}
else if(a[k].val<val)
{
if(a[k].r==-1)return k;
return askpre(a[k].r,val);
}
if(a[k].l==-1)
{
long long p=a[k].f;
while(p!=-1&&k==a[p].l)k=p,p=a[p].f;
return p;
}
k=a[k].l;
while(a[k].r!=-1)k=a[k].r;
return k;
}
int asknex(int k,int val) //求后继
{
if(val<a[k].val)
{
if(a[k].l==-1)return k;
return asknex(a[k].l,val);
}
else if(val>a[k].val)
{
if(a[k].r==-1)
{
int p = a[k].f;
while( p!=-1&&k==a[p].r)k = p,p = a[p].f;
return p;
}
return asknex(a[k].r,val);
}
if(a[k].r==-1)
{
int p = a[k].f;
while( p!=-1&& k == a[p].r )k = p,p = a[p].f;
return p;
}
k=a[k].r;
while( a[k].l!=-1 )k = a[k].l;
return k;
}
void Delete(int val) //单点删除
{
long long pre=askpre(root,val);
long long nex=asknex(root,val);
if(pre!=-1&&nex!=-1)
{
splay(pre,-1);
splay(nex,pre);
if(a[a[nex].l].num>1)a[a[nex].l].num--;
else a[nex].l=-1;
maintain(a[nex].l); //删除后及时更新数据,顺序不能反
maintain(nex);
maintain(pre);
}
else if(pre!=-1&&nex==-1)
{
splay(pre,-1);
if(a[pre].r!=-1&&a[a[pre].r].val==val)
{
if(a[a[pre].r].num>1)a[a[pre].r].num--;
else a[pre].r=-1;
}
maintain(a[pre].r);
maintain(pre);
}
else if(pre==-1&&nex!=-1)
{
splay(nex,-1);
if(a[nex].l!=-1&&a[a[nex].l].val==val)
{
if(a[a[nex].l].num>1)a[a[nex].l].num--;
else a[nex].l=-1;
}
maintain(a[nex].l);
maintain(nex);
}
}
int main()
{
int T;cin>>T;
root=-1,size=0;
while(T--)
{
int x,op;
scanf("%d%d",&op,&x);
if(op==1)insert(root,x);
if(op==2)Delete(x);
if(op==3)printf("%d\n",search(root,x));
if(op==4)printf("%d\n",ask(x));
if(op==5)printf("%d\n",a[askpre(root,x)].val);
if(op==6)printf("%d\n",a[asknex(root,x)].val);
//show(root);
}
return 0;
}
相关文章推荐
- 【BZOJ3224】【codevs4543】【tyvj1728】普通平衡树,第一次的splay
- BZOJ 3224 Tyvj 1728 普通平衡树 (Splay)
- 【bzoj3224】【Tyvj1728】【普通平衡树】【splay】
- 【Splay】bzoj3224 Tyvj 1728 普通平衡树
- bzoj 3224: Tyvj 1728 普通平衡树(splay 模板题)
- 【模板】【bzoj3224】Tyvj 1728 普通平衡树 Splay
- bzoj 3224==tyvj 1728普通平衡树 splay
- bzoj 3224: Tyvj 1728 普通平衡树 (Splay模板)
- BZOJ 3224 Tyvj 1728 普通平衡树 | Splay 板子+SPlay详细讲解
- bzoj 3224 Tyvj 1728 普通平衡树 [Splay]
- [bzoj 3224] Tyvj 1728 普通平衡树(Splay)
- BZOJ 3224: Tyvj 1728 普通平衡树 [Splay]【数据结构】
- _bzoj3224 Tyvj 1728 普通平衡树【Splay】
- bzoj3224: Tyvj 1728 普通平衡树(打个splay暖暖手)
- [bzoj3224]Tyvj 1728 普通平衡树——splay模板
- 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树
- bzoj 3224 Tyvj 1728 普通平衡树 (替罪羊树模板)
- bzoj3224: Tyvj 1728 普通平衡树(平衡树)
- 3224: Tyvj 1728 普通平衡树
- BZOJ 3224: Tyvj 1728 普通平衡树