二分枚举答案,问题转化为计算至少取到一定体积,价格最少是多少,显然是贪心取最小,用线段树维护,然后因为要判断答案,所以可持久化一下即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define mid (l+r>>1) 5 #define ll long long 6 struct ji{ 7 int d,p,l; 8 bool operator < (const ji &a)const{ 9 return d>a.d; 10 } 11 }a[N]; 12 int V,n,m,r[N],ls[N*20],rs[N*20]; 13 ll x,y,sz[N*20],f[N*20]; 14 void update(int k1,int &k2,int l,int r,int x,int y){ 15 k2=++V; 16 if (l==r){ 17 sz[k2]=sz[k1]+y; 18 f[k2]=f[k1]+1LL*y*l; 19 return; 20 } 21 ls[k2]=ls[k1]; 22 rs[k2]=rs[k1]; 23 if (x<=mid)update(ls[k1],ls[k2],l,mid,x,y); 24 else update(rs[k1],rs[k2],mid+1,r,x,y); 25 sz[k2]=sz[ls[k2]]+sz[rs[k2]]; 26 f[k2]=f[ls[k2]]+f[rs[k2]]; 27 } 28 ll query(int k,int l,int r,ll x){ 29 if (l==r)return l*x; 30 if (x<sz[ls[k]])return query(ls[k],l,mid,x); 31 return query(rs[k],mid+1,r,x-sz[ls[k]])+f[ls[k]]; 32 } 33 int main(){ 34 scanf("%d%d",&n,&m); 35 for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].d,&a[i].p,&a[i].l); 36 sort(a+1,a+n+1); 37 for(int i=1;i<=n;i++)update(r[i-1],r[i],1,N-5,a[i].p,a[i].l); 38 for(int i=1;i<=m;i++){ 39 scanf("%lld%lld",&x,&y); 40 if ((y>sz[r[n]])||(query(r[n],1,N-5,y)>x)){ 41 printf("-1\n"); 42 continue; 43 } 44 int l=1,rr=n; 45 while (l<rr){ 46 int t=(l+rr>>1); 47 if ((y>sz[r[t]])||(query(r[t],1,N-5,y)>x))l=t+1; 48 else rr=t; 49 } 50 printf("%d\n",a[l].d); 51 } 52 }