题目描述
您需要写一种数据结构,来维护一些数( 都是 10^9 以内的数字)的集合,最开始时集合是空的。其中需要提供以下操作,操作次数 q 不超过 10^4:
- 查询 x 数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,应输出最小的排名)。
- 查询排名为 x 的数。
- 求 x 的前驱(前驱定义为小于 x,且最大的数)。若未找到则输出 -2147483647。
- 求 x 的后继(后继定义为大于 xx,且最小的数)。若未找到则输出 2147483647。
- 插入一个数 x。
输入格式
无
输出格式
无
输入输出样例
7 2 5 1 3 5 3 1 5 5 5 1 3 2 2 3 3 4 3
题目分析
首先分析题目的输入格式,输入的第一行是总共要执行的操作次数q,接下来q行每行两个数字,第一个数字n是所需要执行的操作序号(1-5之间),第二个数字则是题目中的x
关于lower_bound和upper_bound:
lower_bound(begin,end,x)求的是begin-end中第一个大于x的数
upper_bound(begin,end,x)求的是begin-end中第一个大于等于x的数
注意,它们传回的都是指针,如果在后面-a(a是数组),那么返回的就是x所在的位置
接下来依次来看这5个操作该如何执行(假设数组为a,s是数组长度,s初始值为s=0
5.插入一个数 x
先讲操作5,因为只有插入了x,数组a才不是空的,操作1、2、3、4才有意义。
为了方便计算,插入的第一个数即记为a[1],第二个数为a[2]……,所以,语句应为a[++s]=x (注意这里是++s而不是s++,因为++s是先加一的,保证了输入的第一个x为a[1]而不是a[0])
接下来是最重要的,每一次插入之后,要用sort函数对数组a进行排序,这样保证每一次执行剩下的四个操作的时候,数组a都是从小到大排列的。
1.查询 x 数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,应输出最小的排名)
这个其实就是用lower_bound(a+1,a+s+1,x)-a,返回的位置就是x数的排名。
2.查询排名为 x 的数
这个也比较简单,输出a[x]就可以。
3.求 x 的前驱(前驱定义为小于 x,且最大的数)。若未找到则输出 -2147483647。
这个可以先用lower_bound(a+1,a+s+1,x)-a,得到第一个大于等于x的数所在的位置t,由于a是从小到大排列的,那么如果t不等于1,那么t的上一个数字肯定就是小于x且最大的数,输出a[t-1]就可以,而如果t=1,就说明没有比x小的数了,这时候按照题目条件,应该输出-2147483647。
4.求 x的后继(后继定义为大于 x,且最小的数)。若未找到则输出 2147483647。
这个就是用upper_bound(a+1,a+s+1,x)求得大于x的第一个数,由于数组a从小到大排列,所以这个数便是题目要求的数。如果这个数等于a+s+1,就是没找到,输出2147483647。
代码:
#include <iostream> #include <algorithm> using namespace std; int a[10001]; int main() { int q,i,n,x,s=0; cin>>q;//输入总共要查询的总数 for(i=0;i<q;i++) { cin>>n;//输入要问的问题 cin>>x;//输入x if(n==1) cout<<lower_bound(a+1,a+s+1,x)-a<<endl; else if(n==2) cout<<a[x]<<endl; else if(n==3) { int t=lower_bound(a+1,a+s+1,x)-a;//第一个大于等于的 if(t==1) cout<<-2147483647<<endl;//没有比它小的了 else cout<<a[t-1]<<endl;//它的上一个就是小于x但最大的 } else if(n==4) { int *t=upper_bound(a+1,a+s+1,x); if(t==a+s+1) cout<<2147483647<<endl;//没找到 else cout<<*t<<endl; } else if(n==5) { a[++s]=x;//插入x,注意s++和++s,++s是先加一再执行 sort(a+1,a+s+1);//排序 } } return 0; }
(参考洛谷题解)