P4602 [CTSC2018] 混合果汁
贪心思想,整体二分+权值线段树解决。
\(Step\ 1\) 首先将所有果汁的美味度按从大到小排序,若美味度高的果汁可以满足小朋友的两个需求,则储存答案。
\(Step\ 2\) 不断二分果汁,并且枚举小朋友,若当前果汁能满足小朋友的两个要求,则将小朋友分流到左区间,否则则分流到右区间。其中左区间会提高果汁的美味度,右区间会减少。
\(Step\ 3\) 分流小朋友致叶子节点后,将这个区间的小朋友给予当前美味度的果汁,理由同 \(Step\ 1\)。
现在考虑如何维护小朋友的两个需求,以果汁的价格为权值构造权值线段树,维护当前左区间内的果汁价格,并与小朋友的消费能力比较,筛选出小朋友。
记得开 long long。
#include <bits/stdc++.h>
using namespace std;
long long read(){
long long x=0;
int f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){ if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
inline void put(int x){
if(x<0){putchar('-');x=-x;}
if(x>=10) put(x/10);
putchar(x%10+'0');
}
#define p2 p<<1
#define p3 p<<1|1
const int N=1e5+7;
int n,m;
struct Juice{
int d,p,l;
bool operator <(Juice x) {
return d>x.d;
}
}a[N];
struct kids{
long long g,l;
int id;
}q[N],q1[N],q2[N];
long long vol[N<<2],mon[N<<2];
int idx;
int ans[N];
void pushup(int p){
vol[p]=vol[p2]+vol[p3];
mon[p]=mon[p2]+mon[p3];
}
void add(int p,int l,int r,int Jp,int Jl){
if(l==r){
vol[p]+=Jl;
mon[p]=vol[p]*l;
return;
}
int mid=(l+r)>>1;
if(Jp<=mid) add(p2,l,mid,Jp,Jl);
else add(p3,mid+1,r,Jp,Jl);
pushup(p);
}
long long query(int p,int l,int r,long long v){
if(!v) return 0;
if(l==r) return l*v;//价格的零头
int mid=(l+r)>>1;
if(vol[p2]>=v) return query(p2,l,mid,v);
else return mon[p2]+query(p3,mid+1,r,v-vol[p2]);
}
void Work(int l,int r,int L,int R){
if(l>r) return;
if(L==R){//当前区间的小朋友可以适配果汁 L。
for(int i=l;i<=r;i++) ans[q[i].id]=a[L].d;
return;
}
int mid=(L+R)>>1,p0=0,p1=0;
while(idx<mid) idx++,add(1,1,N,a[idx].p,a[idx].l);//维护当前左区间内的果汁价格
while(idx>mid) add(1,1,N,a[idx].p,-a[idx].l),idx--;
for(int i=l;i<=r;i++){//筛选出适配的小朋友
if(vol[1]>=q[i].l&&query(1,1,N,q[i].l)<=q[i].g) q1[++p0]=q[i];
else q2[++p1]=q[i];
}
for(int i=1;i<=p0;i++) q[l+i-1]=q1[i];
for(int i=1;i<=p1;i++) q[l+p0+i-1]=q2[i];
Work(l,l+p0-1,L,mid);
Work(l+p0,r,mid+1,R);
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
n=read(),m=read();
for(int i=1;i<=n;i++) {
a[i].d=read(),a[i].p=read(),a[i].l=read();
}
a[++n]={-1,0,N};//无解的小朋友会被分流到这里
sort(a+1,a+1+n);//贪心,排序
for(int i=1;i<=m;i++){
q[i].g=read(),q[i].l=read();
q[i].id=i;
}
Work(1,m,1,n);
for(int i=1;i<=m;i++) put(ans[i]),putchar('\n');
return 0;
}

浙公网安备 33010602011771号