【bzoj3224】【Tyvj 1728】 普通平衡树 树状数组

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

数据范围:操作数105x109

 

这一题用平衡树做的方法是显然的,然而平衡树太长太慢,我们考虑写一个优美一点的算法。

首先先离散化所有读入的数(别离散化操作4!!!!)

然后,插入和删除操作显然(直接在离散化后的x处,赋值+1或者-1即可)

查询某个数的排名也是显然的。

考虑查询排名为x如何高速完成,此处不妨设x为正整数。

我们求一个最小的p,使得2pcnt,其中cnt为树状数组的长度。

设当前访问到的点为id(初始为0

我们每次查询a[id+2p]上的值是否小于x,如果是x,那么id+=2p,然后x=a[id]

然后p--即可。

最后输出id+1即是第k大的数。

求前驱和后继:先求出给出的数是第几大的,然后+11即可。

代码奇短

复制代码
 1 #include<bits/stdc++.h>
 2 #define M 200000
 3 #define lowbit(x) ((x)&(-x))
 4 using namespace std;
 5 int a[M]={0},c[M]={0},n,cnt=0,m;
 6 int op[M]={0},b[M]={0};
 7 void add(int x,int k){for(;x<=n;x+=lowbit(x)) a[x]+=k;}
 8 int sum(int x){int k=0;for(;x;x-=lowbit(x)) k+=a[x]; return k;}
 9 int getkth(int k){
10     int id=0;
11     for(int i=n;i;i>>=1){
12         if(k>a[id+i]) 
13         k-=a[id+i],id+=i;
14     }
15     return id+1;
16 }
17 int main(){
18     scanf("%d",&m);
19     for(int i=1;i<=m;i++){
20         scanf("%d%d",op+i,b+i);
21         if(op[i]!=4) c[++cnt]=b[i];
22     }
23     sort(c+1,c+cnt+1);
24     for(int i=1;i<=m;i++)
25     if(op[i]!=4) b[i]=lower_bound(c+1,c+cnt+1,b[i])-c;
26     for(n=1;n<=cnt;n<<=1);    
27     for(int i=1;i<=m;i++){
28         if(op[i]==1) add(b[i],1);
29         if(op[i]==2) add(b[i],-1);
30         if(op[i]==3) printf("%d\n",sum(b[i]-1)+1);
31         if(op[i]==4) printf("%d\n",c[getkth(b[i])]);
32         if(op[i]==5) printf("%d\n",c[getkth(sum(b[i]-1))]);
33         if(op[i]==6) printf("%d\n",c[getkth(sum(b[i])+1)]);
34     }
35 }    
复制代码
posted @   AlphaInf  阅读(304)  评论(2编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示