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;
}
posted @ 2024-04-21 21:55  shoot_down  阅读(50)  评论(0)    收藏  举报