luogu4602 混合果汁 (主席树)

时间:2023-03-09 09:33:08
luogu4602 混合果汁 (主席树)

按照美味值从大到小排序,对于每个询问,我想二分找到一个前缀来满足条件

那么以单价为下标建主席树,维护区间的最大体积和 以及满足这个最大体积需要的价钱

然后二分答案,再在主席树上二分,找到恰好满足的那个位置(肯定是单价越小越好)

复杂度$O(nlog^2n)$

 #include<bits/stdc++.h>
#define CLR(a,x) memset(a,x,sizeof(a))
#define MP make_pair
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pa;
const int maxn=1e5+,maxp=4e6+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Juice{
int l,d,p;
}jui[maxn];
int N,M,rt[maxn];
int ch[maxp][],pct;
ll suml[maxp],sumv[maxp]; inline bool cmp(Juice a,Juice b){return a.d>b.d;} inline void add(int pre,int &p,int l,int r,int x,int y){
p=++pct;
suml[p]=suml[pre]+y,sumv[p]=sumv[pre]+1ll*y*x;
if(l<r){
int m=l+r>>;
if(x<=m) ch[p][]=ch[pre][],add(ch[pre][],ch[p][],l,m,x,y);
else ch[p][]=ch[pre][],add(ch[pre][],ch[p][],m+,r,x,y);
}
} inline bool judge(int p,int l,int r,ll g,ll v){
int m=l+r>>;
// printf("~%d %d\n",l,r);
if(l==r){
if(suml[p]>=v) return l*v<=g;
else return ;
}
int a=ch[p][];
if(suml[a]<v){
v-=suml[a],g-=sumv[a];
if(g<=) return ;
return judge(ch[p][],m+,r,g,v);
}else{
return judge(ch[p][],l,m,g,v);
}
} int main(){
//freopen("","r",stdin);
int i,j,k;
N=rd(),M=rd();
for(i=;i<=N;i++){
jui[i].d=rd(),jui[i].p=rd(),jui[i].l=rd();
}sort(jui+,jui+N+,cmp);
for(i=;i<=N;i++) add(rt[i-],rt[i],,1e5,jui[i].p,jui[i].l);
jui[N+].d=-;
for(i=;i<=M;i++){
ll g=rd(),v=rd();
int l=,r=N+,ans=N+;
while(l<=r){
int m=l+r>>;
if(judge(rt[m],,1e5,g,v)) ans=m,r=m-;
else l=m+;
}
printf("%d\n",jui[ans].d);
}
return ;
}