首先二分$d$,那么要取最小价值,就要在所有满足$d_i\ge d$的$i$中选$p_i$最小的,一路取到$L$。这个东西和名次树很类似,可以在权值线段树上二分。
而快速找到$d_i\ge d$的数据构成的线段树明显是排序+可持久化了。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100050;
char rB[1<<21],*rS,*rT;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline ll rd(){
char c=gc();
while(c<48||c>57)c=gc();
ll x=c&15;
for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
return x;
}
int lc[N<<5],rc[N<<5],sz=0,rt[N];
ll cnt[N<<5],sum[N<<5],sr[N];
struct node{
int d,p,l;
}a[N];
inline bool cmp(node a,node b){return a.d<b.d;}
int ins(int pre,int L,int R,int x,int k){
int o=++sz;
cnt[o]=cnt[pre]+k;sum[o]=sum[pre]+(ll)x*k;
if(L<R){
int M=L+R>>1;
if(x<=M){lc[o]=ins(lc[pre],L,M,x,k);rc[o]=rc[pre];}
else{rc[o]=ins(rc[pre],M+1,R,x,k);lc[o]=lc[pre];}
}
return o;
}
ll query(int o,int L,int R,ll lim){
if(L==R)return lim*L;
int M=L+R>>1;
if(cnt[lc[o]]>=lim)return query(lc[o],L,M,lim);
return sum[lc[o]]+query(rc[o],M+1,R,lim-cnt[lc[o]]);
}
int main(){
int n=rd(),q=rd(),i,l,r,mid;
ll g,lim;
for(i=1;i<=n;++i){a[i].d=rd();a[i].p=rd();a[i].l=rd();}
sort(a+1,a+n+1,cmp);
for(i=n;i;--i){
sr[i]=sr[i+1]+a[i].l;
rt[i]=ins(rt[i+1],1,100000,a[i].p,a[i].l);
}
while(q--){
g=rd();lim=rd();
l=0;r=n;
while(l<r){
mid=l+r+1>>1;
if(sr[mid]>=lim&&query(rt[mid],1,100000,lim)<=g)l=mid;
else r=mid-1;
}
if(!l)puts("-1");
else printf("%d\n",a[l].d);
}
return 0;
}
