题目:https://loj.ac/problem/2555
二分答案,在可以选的果汁中,从价格最小的开始选。
按价格排序,每次可以选的就是一个前缀。对序列建主席树,以价格为角标,维护体积和、体积*价格和。
一开始忘记离散化价格了。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define ls Ls[cr] #define rs Rs[cr] using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } ll rdl() { ll ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int N=1e5+5,M=N*20; int n,tp[N],dy[N],tot,rt[N],Ls[M],Rs[M];ll sl[M],sm[M]; struct Node{ int d,p,l; bool operator< (const Node &b)const {return d>b.d;} }a[N]; int nwnd(int pr) { int cr=++tot; ls=Ls[pr];rs=Rs[pr]; sl[cr]=sl[pr]; sm[cr]=sm[pr]; return cr; } void ins(int l,int r,int &cr,int pr,int p,int k,ll s) { cr=nwnd(pr); sl[cr]+=k; sm[cr]+=s; if(l==r)return; int mid=l+r>>1; if(p<=mid)ins(l,mid,ls,Ls[pr],p,k,s); else ins(mid+1,r,rs,Rs[pr],p,k,s); } bool chk(int l,int r,int cr,ll g,ll lm) { if(l==r) { if(sl[cr]<lm||lm*tp[l]>g)return false; return true;} int mid=l+r>>1; if(sl[ls]>=lm)return chk(l,mid,ls,g,lm); lm-=sl[ls]; g-=sm[ls]; if(g<=0)return false; return chk(mid+1,r,rs,g,lm); } int main() { n=rdn(); int Q=rdn(); for(int i=1;i<=n;i++) { a[i].d=rdn();a[i].p=rdn();a[i].l=rdn(); tp[i]=a[i].p; } sort(a+1,a+n+1); sort(tp+1,tp+n+1); int m=unique(tp+1,tp+n+1)-tp-1; for(int i=1;i<=n;i++) { int d=lower_bound(tp+1,tp+m+1,a[i].p)-tp; ins(1,m,rt[i],rt[i-1],d,a[i].l,(ll)a[i].p*a[i].l); } ll g,lm; int ans,l,r; while(Q--) { g=rdl();lm=rdl(); ans=0; l=1; r=n; while(l<=r) { int mid=l+r>>1; if(chk(1,m,rt[mid],g,lm))ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans?a[ans].d:-1); } return 0; }