传送门
整体二分好题。
题意简述:nnn种果汁,每种有三个属性:美味度,单位体积价格,购买体积上限。
现在有mmm个询问,每次问能否混合出总体积大于某个值,总价格小于某个值的果汁,如果能,求所有方案中用于混合的果汁的美味度的最小值的最大值。
思路:
首先考虑单次询问怎么做,看这个询问的类型应该可以二分答案。
接着思考如何checkcheckcheck,这个时候可以发现果汁可以按照美味度单调递减排列来让我们二分这个答案。
拍完序之后就可以采用贪心的方式,我们知道应该从单位体积从小到大买,因此我们建一棵权值线段树在上面二分寻找如果要满足购买那么多体积需要的最小花费,然后跟允许的花费比较进行下一次二分。
可以观察到对于所有的询问这样的操作形式都是一模一样的,因此我们整体二分即可。
一个判无解的小技巧:加入一种美味度为-1,单位体积价格为0,购买上限为inf*的饮料,这样无解的自然会二分到这个点上
代码:
#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
#define ri register int
using namespace std;
typedef long long ll;
inline ll read(){
ll ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=1e5+5,mx=100000;
int n,m,ans[N],cur=0;
ll s1[N<<2],s2[N<<2];
struct Upd{int d,p,l;}a[N];
struct Q{int id;ll g,l;}qry[N],t1[N],t2[N];
inline void pushup(int p){s1[p]=s1[lc]+s1[rc],s2[p]=s2[lc]+s2[rc];}
inline void update(int p,int l,int r,int k,int v){
if(l==r){s1[p]+=v,s2[p]+=(ll)v*l;return;}
if(k<=mid)update(lc,l,mid,k,v);
else update(rc,mid+1,r,k,v);
pushup(p);
}
inline ll query(int p,int l,int r,int v){
if(!v)return 0;
if(l==r)return (ll)v*l;
if(s1[lc]>=v)return query(lc,l,mid,v);
return s2[lc]+query(rc,mid+1,r,v-s1[lc]);
}
inline bool cmp(const Upd&a,const Upd&b){return a.d>b.d;}
inline void solve(int ql,int qr,int l,int r){
if(ql>qr||l>r)return;
if(l==r){for(ri i=ql;i<=qr;++i)ans[qry[i].id]=a[l].d;return;}
int hd1=0,hd2=0;
while(cur<mid)++cur,update(1,1,mx,a[cur].p,a[cur].l);
while(cur>mid)update(1,1,mx,a[cur].p,-a[cur].l),--cur;
for(ri i=ql;i<=qr;++i){
if(qry[i].l>s1[1])t2[++hd2]=qry[i];
else if(query(1,1,mx,qry[i].l)<=qry[i].g)t1[++hd1]=qry[i];
else t2[++hd2]=qry[i];
}
for(ri i=1;i<=hd1;++i)qry[ql+i-1]=t1[i];
for(ri i=1;i<=hd2;++i)qry[ql+hd1+i-1]=t2[i];
solve(ql,ql+hd1-1,l,mid),solve(ql+hd1,qr,mid+1,r);
}
int main(){
n=read(),m=read();
for(ri i=1;i<=n;++i)a[i].d=read(),a[i].p=read(),a[i].l=read();
a[++n]=(Upd){-1,0,0x3f3f3f3f};
sort(a+1,a+n+1,cmp);
for(ri i=1;i<=m;++i)qry[i].id=i,qry[i].g=read(),qry[i].l=read();
solve(1,m,1,n);
for(ri i=1;i<=m;++i)cout<<ans[i]<<'\n';
return 0;
}