洛谷P3963 [TJOI2013]獎學金
阿新 • • 發佈:2018-12-15
堆
首先這道題不可二分,自己YY一下挺顯然的。
把每個人按照成績排序,從大往小掃,用三個可刪除的堆維護。分別維護當前位置左右的前大,維護左邊不是前大的,相當於的後備。
具體實現見程式碼:
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define F inline
using namespace std;
typedef long long LL;
struct data{ int x; LL w; }a[N];
struct Q{
priority_queue<LL> q,d;
F void push(LL x){ q.push(x); }
F void erase(LL x){ d.push(x); }
F LL top(){
while (!d.empty()&&q.top()==d.top())
q.pop(),d.pop(); return q.top( );
}
F void pop(){
while (!d.empty()&&q.top()==d.top())
q.pop(),d.pop(); q.pop();
}
F LL size(){ return q.size()-d.size(); }
}q1,q2,q3;
int c,n; LL f,s1,s2;
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read (){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
F bool cmp1(data a,data b){ return a.w<b.w; }
F bool cmp2(data a,data b){ return a.x<b.x; }
F int pd(){
for (int i=1;i<n-c/2;i++){
if (q1.size()<c/2) q1.push(a[i].w),s1+=a[i].w;
else if (q1.top()>a[i].w)
q2.push(-q1.top()),s1-=q1.top()-a[i].w,q1.pop(),q1.push(a[i].w);
else q2.push(-a[i].w);
}
for (int i=n-c/2+1;i<=n;i++) q3.push(a[i].w),s2+=a[i].w;
for (int i=n-c/2;i>c/2;i--){
if (s1+s2+a[i].w<=f) return i;
if (q3.top()>a[i].w) s2+=a[i].w-q3.top(),q3.pop(),q3.push(a[i].w);
if (q1.top()<a[i-1].w) q2.erase(-a[i-1].w);
else q1.erase(a[i-1].w),q1.push(-q2.top()),s1-=q2.top()+a[i-1].w,q2.pop();
}
}
int main(){
c=_read(),n=_read(),f=_read();
for (int i=1;i<=n;i++) a[i].x=_read(),a[i].w=_read();
sort(a+1,a+n+1,cmp1);
for (LL i=1,s=0;i<=c;i++)
if ((s+=a[i].w)>f) return puts("-1"),0;
sort(a+1,a+n+1,cmp2);
return printf("%d\n",a[pd()].x),0;
}