考虑二分答案+可持久化线段树。
对于这种最大化最小值的问题,通常使用二分来解决。于是我们想到了对果汁按其d值排序。然后使用下标为费用的一棵可持久化线段树来维护费用。
check函数可以这样写:如果我们发现以mid为根的线段树本身还不够li升,就可以直接返回0了,否则贪心地查询其最小花费,如果也符合要求,那么就返回1
于是这题就是这样:先对果汁按美味度排序,然后按单价丢进一棵主席树中,最后对于询问,二分答案并贪心验证。
这真是一道比较水的CTSC
参考代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define int long long 6 #define N 200005 7 using namespace std; 8 int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 13 return x*f; 14 } 15 struct node{int d,p,l;}juice[N]; 16 struct hjt_tree{int ls,rs,w,l;}t[N*21]; 17 bool cmp(node a,node b){if(a.d!=b.d)return a.d<b.d;return a.p<b.p;} 18 int n,m,T[N],MAXP,cnt,limg,liml; 19 void modify(int &node,int last,int l,int r,int x,int ll,int ww) 20 { 21 node=++cnt;t[node]=t[last];t[node].l+=ll,t[node].w+=ww; 22 if(l==r)return; 23 int mid=(l+r)>>1; 24 if(x<=mid)modify(t[node].ls,t[last].ls,l,mid,x,ll,ww); 25 else modify(t[node].rs,t[last].rs,mid+1,r,x,ll,ww); 26 } 27 int query(int node,int l,int r,int w) 28 { 29 if(l==r)return w*l; 30 int mid=(l+r)>>1; 31 if(t[t[node].ls].l>=w)return query(t[node].ls,l,mid,w); 32 else return t[t[node].ls].w+query(t[node].rs,mid+1,r,w-t[t[node].ls].l); 33 } 34 bool check(int mid) 35 { 36 if(liml>limg)return 0; 37 if(t[T[mid]].l>=liml&&query(T[mid],1,MAXP,liml)<=limg)return 1; 38 return 0; 39 } 40 signed main() 41 { 42 n=read();m=read(); 43 for(int i=1;i<=n;i++) 44 { 45 juice[i].d=read();juice[i].p=read();juice[i].l=read(); 46 //MAXP=max(MAXP,juice[i].p); 47 } 48 MAXP=200001; 49 sort(juice+1,juice+1+n,cmp); 50 for(int i=n;i>=1;i--)modify(T[i],T[i+1],1,MAXP,juice[i].p,juice[i].l,juice[i].p*juice[i].l); 51 while(m--) 52 { 53 limg=read();liml=read(); 54 int ans=-1,ll=1,rr=n,mid; 55 while(ll<=rr) 56 { 57 mid=(ll+rr)>>1; 58 if(check(mid))ll=mid+1,ans=mid; 59 else rr=mid-1; 60 } 61 if(ans==-1)printf("-1 "); 62 else printf("%d ",juice[ans].d); 63 } 64 return 0; 65 }