题目链接
Note that the memory limit is unusual.
You are given a multiset consisting of n integers. You have to process queries of two types:
k-th order statistics in the multiset is the k-th element in the sorted list of all elements of the multiset. For example, if the multiset contains elements 1, 4, 2, 1, 4, 5, 7, and k=3, then you have to find the 3-rd element in [1,1,2,4,4,5,7], which is 2. If you try to delete an element which occurs multiple times in the multiset, only one occurence is removed.
After processing all queries, print any number belonging to the multiset, or say that it is empty.
The first line contains two integers n and q (1≤n,q≤1e6) — the number of elements in the initial multiset and the number of queries, respectively.
The second line contains n integers a1, a2, …, an (1≤a1≤a2≤⋯≤an≤n) — the elements of the multiset.
The third line contains q integers k1, k2, …, kq, each representing a query:
if 1≤ki≤n, then the i-th query is “insert ki into the multiset”;
if ki<0, then the i-th query is “remove the |ki|-th order statistics from the multiset”. For this query, it is guaranteed that |ki| is not greater than the size of the multiset.
If the multiset is empty after all queries, print 0.
Otherwise, print any integer that belongs to the resulting multiset.
5 5
1 2 3 4 5
-1 -1 -1 -1 -1
0
5 4
1 2 3 4 5
-5 -1 -3 -1
3
6 2
1 1 1 2 3 4
5 6
6
我看有很多人用线段树和树状数组过的,我看了看题解,觉得挺有意思的,来记录一波,突破点就在只需输出该数组里的一个元素,我们就输出最小的~
关键点就是在于一个函数 f ( x ) f(x) f(x),记录当前小于等于元素 x x x 的数的个数,如果为 0 0 0 直接输出 0 0 0,证明此时集合为空;若不为 0 0 0,则一直二分缩小范围得到 f ( x ) f(x) f(x) 最小的值 x x x 即为答案~
下面看如何计算小于等于 x x x 的个数 c n t cnt cnt,首先在 a a a 数组中找到小于等于 x x x 的所有元素个数,我们用数组 k k k 记录下所有操作数,对当前操作数 o p op op,若 o p > 0 且 o p < = x , c n t + + op>0 且 op<=x,cnt++ op>0且op<=x,cnt++,若 o p < 0 且 o p < = c n t op<0 且 op<=cnt op<0且op<=cnt,即删去的位置都在 x x x 的位置之前, c n t − − cnt-- cnt−−,那么最终 c n t cnt cnt 就是函数返回值~
题目有个坑点就是时限卡了 c i n cin cin,内存限制开两个数组完全够了,应该是针对了用线段树和树状数组做题的人~
AC代码如下:
#include
using namespace std;
typedef long long ll;
vector<int>a,k;
int n,q;
int f(int x){
int cnt=0;
for(auto i:a) if(i<=x) cnt++;
for(auto i:k){
if(i>0 && i<=x) cnt++;
if(i<0 && abs(i)<=cnt) cnt--;
}
return cnt;
}
main(){
scanf("%d%d",&n,&q);
a.resize(n);
k.resize(q);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<q;i++) scanf("%d",&k[i]);
if(f(2e6)==0){
puts("0");
exit(0);
}
int l=0,r=2e6;
while(l<=r){
int mid=(l+r)/2;
if(f(mid)>0) r=mid-1;
else l=mid+1;
}
printf("%d",l);
}