BZOJ 5343: [CTSC2018] 混合果汁

题目在这里呀~

题意

(迟到的题解吧,CTSC略略略,但这道题确实挺基础的qwq)
有n种果汁,m个小朋友,第i种果汁有个美味度di,每升的价格pi,和最多有li升。第i个小朋友付的价格不超过gi,但要获得至少Li升的果汁,问美味度最小值的最大值是多少?

题解

一眼可以看出是二分答案的吧,然后考虑贪心,暴力的话是把美味度>=d[i]的p数组排序,然后从小的开始取,这样子是正确的,但太慢了,所以考虑用数据结构维护,类似于区间第k大的思路,我们以p为线段树下标,点上存价格在[l,r]之间的果汁有多少。用可持久化线段树第i棵树就表示1~i的果汁所对应的线段树。然后…好像就解决的吧?感觉别的没什么好说的了(要不前缀和了解一下?emm这题确实挺简单的ww

//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 200200
using namespace std;
int n,m,maxp,s,cnt,tot,q[N],opp[N],root[N];
long long G,LL,sum[N];

struct leo{
    int d,p,l;
}a[N];

struct Segment_tree{
    int l,r;
    long long val,LL;
}t[2000000];

bool cmp(leo a,leo b)
{
    return a.d<b.d;
}

inline void modify(int &rt,int p,int l,int r,int x,long long delta)
{
    rt=++cnt;
    t[rt].l=t[p].l;t[rt].r=t[p].r;
    t[rt].LL=t[p].LL;t[rt].val=t[p].val;
    t[rt].val+=1ll*x*delta;t[rt].LL+=delta;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(x<=mid) modify(t[rt].l,t[p].l,l,mid,x,delta);
    else modify(t[rt].r,t[p].r,mid+1,r,x,delta);
}

long long query(int rt,int p,int l,int r,long long rest)
{
    if(!rt) return 0;
    if(l==r) return rest*(long long)r;
    int mid=(l+r)>>1;
    long long lsum=t[t[rt].l].LL-t[t[p].l].LL;
    if(rest<=lsum) return query(t[rt].l,t[p].l,l,mid,rest);
    else return t[t[rt].l].val-t[t[p].l].val+query(t[rt].r,t[p].r,mid+1,r,rest-lsum);
}

bool check(int d,long long G,long long LL)
{
    int fr=opp[d];
    //printf("%d %lld\n",d,query(root[n],root[fr-1],1,maxp,LL));
    if(sum[n]-sum[fr-1]<LL) return false;
    if(query(root[n],root[fr-1],1,maxp,LL)<=G) return true;
    return false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a[i].d,&a[i].p,&a[i].l);
        maxp=max(maxp,a[i].p);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].l;
    for(int i=1;i<=n;i++) modify(root[i],root[i-1],1,maxp,a[i].p,a[i].l);
    for(int i=n;i;i--) opp[a[i].d]=i;
    for(int i=1;i<=n;i++) if(a[i].d != a[i-1].d) q[++tot]=a[i].d;
    while(m--){
        scanf("%lld%lld",&G,&LL);
        int L=1,R=tot;
        while(L<R){
            int mid=(L+R+1)>>1;
            if(check(q[mid],G,LL)) L=mid;
            else R=mid-1;
        }
        if(check(q[R],G,LL)) printf("%d\n",q[R]);else puts("-1");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/leo_nasir/article/details/80503544