[bzoj 5343][CTSC2018]混合果汁

传送门

Description

商店里有 \(n\) 种果汁,编号为 \(0,1,\cdots,n-1\)\(i\) 号果汁的美味度是 \(d_i\),每升价格为 \(p_i\)。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中,\(i\)号果汁最多只能添加 \(l_i\)升。

现在有 \(m\) 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 \(j\)个小朋友希望他得到的混合果汁总价格不大于 \(g_j\),体积不小于 \(L_j\)。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。

Solution

整体二分?

开个线段树存当前价格区间能有多少升的果汁以及它们的总价格

对于一个价格\(g\)直接在线段树上二分最多能买多少升果汁


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline ll read()
{
    ll x=0,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-'0';ch=getchar();}
    return x*f;
}
#define MN 100005
#define N 100000
int n,m,ans[MN];
struct juice{
    ll d,p,l;
    bool operator<(const juice &o)const{return d<o.d;}
}J[MN];
struct ques{ll g,l;int id;}q[MN],tmp[MN];
ll T[MN<<2],P[MN<<2];
#define mid ((l+r)>>1)
inline void pushup(int x){T[x]=T[x<<1]+T[x<<1|1];P[x]=P[x<<1]+P[x<<1|1];}
void Modify(int x,int l,int r,ll p,ll L)
{
    if(l==r) return (void)(T[x]+=L,P[x]+=1ll*p*L);
    p<=mid?Modify(x<<1,l,mid,p,L):Modify(x<<1|1,mid+1,r,p,L);
    pushup(x);
}
ll Query(int x,int l,int r,ll g)
{
    if(l==r)
    {
        if(l==0) return T[x];
        return min(T[x],g/l);
    }
    if(g>=P[x<<1]) return T[x<<1]+Query(x<<1|1,mid+1,r,g-P[x<<1]);
    else return Query(x<<1,l,mid,g);
}
void solve(int l,int r,int ql,int qr)
{
    if(l>r||ql>qr) return;
    register int i;
    if(l==r)
    {
        for(i=ql;i<=qr;++i) ans[q[i].id]=J[l].d;
        return;
    }
    register int Mid=(l+r)>>1,lcnt=ql,rcnt=qr;
    for(i=l;i<=Mid;++i) Modify(1,0,N,J[i].p,-J[i].l);
    for(i=ql;i<=qr;++i) Query(1,0,N,q[i].g)>=q[i].l?tmp[rcnt--]=q[i]:tmp[lcnt++]=q[i];
    for(i=ql;i<=qr;++i) q[i]=tmp[i];
    solve(Mid+1,r,rcnt+1,qr);
    for(i=l;i<=Mid;++i) Modify(1,0,N,J[i].p,J[i].l);
    solve(l,Mid,ql,lcnt-1);
}
int main()
{
    n=read();m=read();
    register int i;
    for(i=1;i<=n;++i) J[i].d=read(),J[i].p=read(),J[i].l=read();
    J[++n].d=-1;J[n].p=0;J[n].l=1e18;
    for(i=1;i<=m;++i) q[i].g=read(),q[i].l=read(),q[i].id=i;
    std::sort(J+1,J+n+1);
    for(i=1;i<=n;++i) Modify(1,0,N,J[i].p,J[i].l);
    solve(1,n,1,m);
    for(i=1;i<=m;++i) printf("%d\n",ans[i]);
    return 0;
}



Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/10281748.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值