( ext{Solution:})
题目有三个限制:饮料体积的限制、要求的饮料总体积限制、总价格限制。
首先,美味度最大是我们一定要满足的条件。考虑如何让它变得好维护:
将饮料按照美味度排序,并按顺序建立主席树。
这样,(root_i) 所对应的区间 ([1,i]) 一定是一个美味度递减的区间。这样它就有了单调性。
那么,对于体积和价格的限制咋办呢?
首先,贪心地,价格绝对越小越好。所以,将主席树用来维护下标为价格的值域树。
那么,上面维护啥呢?还剩下一个体积没有考虑,那么我们可以考虑维护体积。
所以,树上维护:到当前点从最便宜的开始能买到多少升饮料,以及需要花费的钱。
那么,考虑每次二分一个答案,由于它具有单调性。
那么我们就可以在树上二分了:在满足体积限制下同时使价格最小。
线段树上二分要注意细节:有可能将所有饮料买完也不够喝;同时如果一个饮料卖不完,观察到这种情况一定出现在叶子。
所以到最后处理即可。如果要递归右区间,记得加上买左区间的钱。
这样,一个 (O(nlog nlog v)) 的算法就出来了。还是在线的。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=5e5+10;
const int INF=1e5+10;
int rt[INF],n,m;
struct T{int ls,sum,rs,sumv;}tr[MAXN<<5];
struct dk{int d,p,l;}q[INF];
int node;
inline int read() {
int s=0,w=1;
char ch=getchar();
while(!isdigit(ch)) {
if(ch=='-')w=-1;
ch=getchar();
}
while(isdigit(ch)) {
s=s*10-48+ch;
ch=getchar();
}
return w*s;
}
int change(int x,int l,int r,int pos,int v){
int p=++node;
tr[p]=tr[x];
tr[p].sum+=pos*v;
tr[p].sumv+=v;
if(l==r)return p;
int mid=(l+r)>>1;
if(pos<=mid)tr[p].ls=change(tr[p].ls,l,mid,pos,v);
else tr[p].rs=change(tr[p].rs,mid+1,r,pos,v);
return p;
}
bool flag;
int query_V(int x,int L,int R,int v){
int mid=(L+R)>>1;
if(L==R) {
if(v>tr[x].sumv) flag=1;
return v*L;
}
if(v<=tr[tr[x].ls].sumv)return query_V(tr[x].ls,L,mid,v);
return query_V(tr[x].rs,mid+1,R,v-tr[tr[x].ls].sumv)+tr[tr[x].ls].sum;
}
void solve(int c,int v){
// c->prive
// v->volume
// Tree was built in c,and should follow the limit of the volume
// consider checking answer:try to guess a delicious_percent,then we should check if is is can be got.
// In the Tree,We have known the least price of this situation.
// We should get the information of the price and volume through this tree.
// Make sure:(Nowprice,Max) we can get sumv and sum(V and price.)
// then we first consider volume.Price has been known and it is decrease.
// we just need get the left position which sumv>V.
// and check the answer.
// int L=1,R=n,ans=-1;
// while(L<=R){
// int mid=(L+R)>>1;
// if(check(mid,v,c))ans=mid,R=mid-1;
// else L=mid+1;
// }
// printf("%d
",ans);
int L=1,R=n,ans=-1,qv=0;
while(L<=R){
int mid=(L+R)>>1;flag=0;
qv=query_V(rt[mid],1,INF,v);
if(qv>c||flag)L=mid+1;
else ans=mid,R=mid-1;
}
ans!=-1?printf("%lld
",q[ans].d):puts("-1");
}
inline bool cmp(dk a,dk b){return a.d==b.d?a.p<b.p:a.d>b.d;}
signed main(){
n=read();m=read();
for(int i=1;i<=n;++i)q[i].d=read(),q[i].p=read(),q[i].l=read();
sort(q+1,q+n+1,cmp);
for(int i=1;i<=n;++i)rt[i]=change(rt[i-1],1,INF,q[i].p,q[i].l);
for(int i=1;i<=m;++i){
int gi=read(),Li=read();
solve(gi,Li);
}
return 0;
}