你需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入一个整数x
2. 删除一个整数x(若有多个相同的数,只删除一个)
3. 查询整数x的排名(若有多个相同的数,输出最小的排名),相同的数依次排名,不并列排名
4. 查询排名为x的数,排名的概念同3
5. 求x的前驱(前驱定义为小于x,且最大的数),保证x有前驱
6. 求x的后继(后继定义为大于x,且最小的数),保证x有后继
你需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入一个整数x
2. 删除一个整数x(若有多个相同的数,只删除一个)
3. 查询整数x的排名(若有多个相同的数,输出最小的排名),相同的数依次排名,不并列排名
4. 查询排名为x的数,排名的概念同3
5. 求x的前驱(前驱定义为小于x,且最大的数),保证x有前驱
6. 求x的后继(后继定义为大于x,且最小的数),保证x有后继
第一行为n,表示操作的个数(n <= 500000)
下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6, -10^7 <= x <= 10^7)
大规模输入数据,建立读入优化
对于操作3,4,5,6每行输出一个数,表示对应答案
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
8
1 10
1 20
1 30
3 20
4 2
2 10
5 25
6 -1
2
20
20
20
好久没诈尸了,不太爽。所以又来一发。。。
学了avl平衡树,才懂得了什么叫做200行代码。。。然而平衡树写得也是一道猥琐过一道,那么就选取最经典的普通平衡树作为这次诈尸的工具吧!
题目与题目描述很直接的告诉了我们——平衡树!所以我们可以很容易分析出实现的方法。
结构体成员配备:左儿子ls,右儿子rs,数值data,高度h,同样数量sum,总结点size(包括左子树、右子树、自己)
维护方式:ls、rs用旋转维护,data永不变更,h取ls和rs的最大h加1,sum删除插入时维护。size在各种时候都别忘了用ls的size、rs的size和sum相加进行维护
1.插入节点。这种简单粗暴的事情还需要说吗?直接进行一般的插入,由于使用惰性删除,所以我们可以遇到相同节点就将sum++,就很容易的解决了!当然你也可以用普通删除然后就保存相同节点啦~
2.删除节点。你们会插入了还不会删除吗?懒人就用惰性删除,你要是真的喜欢普通删除或者希望能过(是的,惰性删除偏偏在学校OJ上过不了TAT,不过大部分OJ都是可以过的),就使用删除后慢慢转到顶部……
3.查询数的排名。这就比较简单了,因为数是一定存在的,所以只要找到一个节点,然后比较大小即可。惰性删除很好解决排名问题,如果刚好等于,只需输出最小的即可,即avl[avl[x].ls].size+1,看出来了吗?ls全体比自己小,排名只需加一,如果比自己小就往ls找,大的话就加上ls的size和sum,再往rs找即可。直接删除就方便了,处理方法一模一样,只是找到一样的后要先记录一下,再往ls那边找(因为有可能有重复的)。
4.查询排名的数。就是3的逆操作,依然是比较ls的size就完了,自己慢慢思考吧……还不需要考虑重复的问题
5.前驱,后继。由于操作过于相似,可以当成一种来看。
直接删除:如果遇到一个节点,比较大小,然后很直接地转入ls或rs即可,不需要考虑其他的。
惰性删除:这就比较麻烦了,如果遇到节点,且sum不为0,那么只需要直接转入ls或rs,因为至少有data比另外一边更接近这个数。但是如果sum为0,就不得不两边兼顾一下,不然很有可能某一边虽然不为空,但可能没有一个符合,现在就只能判断一下是否为空,然后慢慢两边搜……这会浪费一些时间……
至此,我一句代码也没有给你们,然后将这道题讲完了~当然不能坑你们,代码来了(200行+)~
#include
#include
#include
using namespace std;
const int inf=100000000;
int n,cnt,lmax,rmin,root,ans;
inline int getint()
{
register int f=1,p=0;
register char c=getchar();
while((c<'0'||c>'9')&&c!='-')
c=getchar();
if(c=='-')
{
f=-1;c=getchar();
}
for(;c>='0'&&c<='9';)
{
p=p*10+c-'0';
c=getchar();
}
p*=f;
return p;
}
inline void putint(int p)
{
if(p<0)
{
putchar('-');
p=-p;
}
if(p>9)putint(p/10);
putchar(p%10+'0');
}
struct avl
{
int ls,rs,p,h,si,sum;
}d[500005];
inline int zig(int r)
{
register int t=d[r].ls;
d[r].ls=d[t].rs;
d[t].rs=r;
d[r].h=max(d[d[r].rs].h,d[d[r].ls].h)+1;
d[t].h=max(d[d[t].rs].h,d[d[t].ls].h)+1;
d[r].si=d[d[r].ls].si+d[d[r].rs].si+d[r].sum;
d[t].si=d[d[t].ls].si+d[d[t].rs].si+d[r].sum;
return t;
}
inline int zag(int r)
{
register int t=d[r].rs;
d[r].rs=d[t].ls;
d[t].ls=r;
d[r].h=max(d[d[r].rs].h,d[d[r].ls].h)+1;
d[t].h=max(d[d[t].rs].h,d[d[t].ls].h)+1;
d[r].si=d[d[r].ls].si+d[d[r].rs].si+d[r].sum;
d[t].si=d[d[t].ls].si+d[d[t].rs].si+d[r].sum;
return t;
}
inline int zigzag(int r)
{
d[r].rs=zig(d[r].rs);
r=zag(r);
return r;
}
inline int zagzig(int r)
{
d[r].ls=zag(d[r].ls);
r=zig(r);
return r;
}
inline void move(int &q)
{
if(d[d[q].ls].h-d[d[q].rs].h==2)
{
register int t=d[q].ls;
if(d[d[t].ls].h>d[d[t].rs].h)
q=zig(q);
else
q=zagzig(q);
}
else
{
if(d[d[q].ls].h-d[d[q].rs].h==-2)
{
register int t=d[q].rs;
if(d[d[t].rs].h>d[d[t].ls].h)
q=zag(q);
else
q=zigzag(q);
}
}
d[q].si=d[d[q].ls].si+d[d[q].rs].si+d[q].sum;
d[q].h=max(d[d[q].ls].h,d[d[q].rs].h)+1;
}
inline void insert(int a,int &q)
{
if(q==0)
{
q=++cnt;
d[q].p=a;
d[q].h=1;
d[q].si=1;
d[q].sum=1;
return;
}
if(d[q].p==a)
d[q].sum++;
else
{
if(d[q].p>a)
insert(a,d[q].ls);
else
insert(a,d[q].rs);
}
move(q);
}
inline void dele(int a,int q)
{
if(q==0)return;
if(d[q].p==a)
d[q].sum--;
else
{
if(a=d[d[q].ls].si+1&&k<=d[d[q].ls].si+l)return d[q].p;
else
{
if(kx)
{
if(d[q].sum)
rmin=min(rmin,d[q].p);
else
right(x,d[q].rs);
if(d[d[q].ls].si)
right(x,d[q].ls);
}
else
right(x,d[q].rs);
}
int main()
{
n=getint();
for(int i=1;i<=n;i++)
{
register int opt,p;
opt=getint();p=getint();
if(opt==1)
{
insert(p,root);
continue;
}
if(opt==2)
{
dele(p,root);
continue;
}
if(opt==3)
{
ans=ask(p,root);
putint(ans);
}
if(opt==4)
{
ans=find(p,root);
putint(ans);
}
if(opt==5)
{
lmax=-inf;
left(p,root);
putint(lmax);
}
if(opt==6)
{
rmin=inf;
right(p,root);
putint(rmin);
}
putchar('\n');
}
}
我不会说这段代码是会超时的……