题目描述

有一个序列,初始为空。
nn 次操作,每次添加 kk 个值为 aa 的数到序列中。
对于每次操作,你需要输出当前序列的中位数,中位数有 22 个输出较小的一个。其中 1n2×1051\le n\le 2\times 10^51ai1091 \le a_i \le 10^9

思路

因为对于一个数 xx,其中有小于 xx 的书的个数大于 12n\frac{1}{2} n 而且对于任意小于 xx 的数都不成立,那么这个数就是这个序列的中位数,所以这道题目可以使用二分求解。为了快速统计一个序列中小于 xx 的数的个数,可以使用树状数组。将输入在离散化之后一次插入树状数组即可。

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;
}