参考自:https://blog.csdn.net/jhgkjhg_ugtdk77/article/details/38323509
因为是找中位数嘛,所以不必关心这个值的左右到底是谁,只需要知道他可以满足条件即可;
先按照小牛的分数从小到大排个序;
然后我们需要维护这个小牛的左边和右边(n/2)个小牛的最小资助金额;
根据分析,就有了结构体:
struct Cow{
long long val//小牛的分数;
int need//资助金额;
long long lift//表示小牛左边的最小资助金额;
long long right//表示小牛右边的最小资助金额;
}a[maxn];
最后只需要从大到小枚举 need+lift+right<=f的就可以啦;
用一个优先队列存资助额;
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<utility>
#include<queue>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const double epos=1e-8;
const int maxn=1e5+7;
struct Cow{
ll val;
int need;
ll lift;
ll right;
}a[maxn];
bool cmp(const Cow& x,const Cow& y){
return x.val<y.val;
}
priority_queue<int>q;
int main(){
ll f;
int n,c;
int t=0;
ll val;
int need;
scanf("%d%d%lld",&n,&c,&f);
for(int i=0;i<c;i++){
scanf("%lld%d",&val,&need);
if(need<=f){
a[t].val=val;
a[t].need=need;
++t;
}
}
sort(a,a+t,cmp);
if(n>1){
ll sum=0;
//因为要找中位数,所以开头的n/2个元素肯定是不能选择的;
for(int i=0;i<n/2;i++){
sum+=a[i].need;
q.push(a[i].need);
}
//找左边的;
for(int i=n/2;i<c-n/2;i++){
a[i].lift=sum;
int t=a[i].need;
int hh=q.top();
if(t<hh){//如果当前的小牛的资助额更小,则更新,方便下一头牛;
sum=sum-hh+t;
q.pop();
q.push(t);
}
}
while(!q.empty()) q.pop();
sum=0;
//同上;
for(int i=c-1;i>=c-n/2;i--){
sum+=a[i].need;
q.push(a[i].need);
}
//找右边的;
for(int i=c-n/2-1;i>=n/2;i--){
a[i].right=sum;
int t=a[i].need;
int hh=q.top();
if(t<hh){
sum=sum-hh+t;
q.pop();
q.push(t);
}
}
}
ll ans=-1;
for(int i=c-n/2-1;i>=n/2;i--)
if(a[i].need+a[i].lift+a[i].right<=f){
ans=a[i].val;
break;
}
printf("%lld\n",ans);
return 0;
}