[COCI2022-2023#4] Vrsta 的题解
题目描述
有一个序列,初始为空。
有 \(n\) 次操作,每次添加 \(k\) 个值为 \(a\) 的数到序列中。
对于每次操作,你需要输出当前序列的中位数,中位数有 \(2\) 个输出较小的一个。其中 \(1\le n\le 2\times 10^5\),\(1 \le a_i \le 10^9\)。
思路
因为对于一个数 \(x\),其中有小于 \(x\) 的书的个数大于 \(\frac{1}{2} n\) 而且对于任意小于 \(x\) 的数都不成立,那么这个数就是这个序列的中位数,所以这道题目可以使用二分求解。为了快速统计一个序列中小于 \(x\) 的数的个数,可以使用树状数组。将输入在离散化之后一次插入树状数组即可。
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,cnt,ans;
struct edge{int x,id;}b[N];
struct node{int x,num;}a[N];
bool cmp(edge a,edge b){return a.x<b.x;};
struct rmq{
int s[N];
#define lowbit(x) x&-x
void updata(int x,int v){
for(int i=x;i<=n;i+=lowbit(i)) s[i]+=v;
}int sum(int x){
int ans=0;
for(int i=x;i>=1;i-=lowbit(i)) ans+=s[i];
return ans;
}
}x;
bool ck(int mid){
if(x.sum(mid)>=cnt/2+(cnt%2!=0)) return 1;
return 0;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].num;
b[i].x=a[i].x,b[i].id=i;
}sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++) a[b[i].id].x=i;
for(int i=1;i<=n;i++){
x.updata(a[i].x,a[i].num),cnt+=a[i].num;
int l=1,r=n;
while(l<=r){
int mid=(l+r)/2;
if(ck(mid)) ans=mid,r=mid-1;
else l=mid+1;
}cout<<b[ans].x<<endl;
}return 0;
}