CodeForces 1354D Multiset 题解
神奇的二分答案!
首先我们可以考虑输出集合中最大的数。
然后二分一个 \(mid\) 表示是否有一个数大于等于 \(mid\)。
然后你惊奇地发现,可以 \(O(n+q)\) 维护小于 \(mid\) 的数的数量 \(num\)。
总时间复杂度仅为 \(O((n+q)logn)\)。
(好像没什么人写这个解法)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mit map<int,int>::iterator
#define sit set<int>::iterator
#define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
#define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
#define ltype int
#define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
#define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
#define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
#define pii pair<int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
#define fastio ios::sync_with_stdio(false)
const int inf=0x3f3f3f3f,mod=1000000007;
const double pi=3.1415926535897932,eps=1e-6;
void chmax(int &x,int y){if(x < y) x = y;}
void chmin(int &x,int y){if(x > y) x = y;}
int n,m,a[1000005],b[1000005],del;
bool check(int k){
int p = 0, siz = 0;
// p 最后一个小于k的元素的下标
rep(i,1,n) if(a[i] < k) p++;
siz = n;
rep(i,1,m) {
if(b[i] > 0) {
if(b[i] < k) p++;
siz++;
}
else {
if(-b[i] <= p) p--;
siz--;
}
}
return p < siz;
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%d",a+i);
rep(i,1,m) {scanf("%d",b+i);del += (b[i] < 0);}
if(n + (m - del) - del == 0){
puts("0");
return 0;
}
int l = 1,r = n;
while(l < r){
int mid = (l + r + 1) >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l);
return 0;
}