KKiseki的博客

要赌上的不是微小的奇迹,而是一直以来的全部光阴

洛谷4602:混合果汁(可持久化线段树+二分)

刚刚吃饭时突然想起今天做了题ntt
但怎么也想不起题目
所以还是稍微写写博客
题面

最小值最大,哼,二分
二分后就是在某几种果汁中求出固定体积的最小价值
可以用线段树维护
对于是美味度大于某个值的这个条件
把线段树可持久化掉就好

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const int N=200200;
const LL oo=2e18;

struct yy
{
    int d,p,l;
}f[N];

bool cmp(yy x,yy y)
{
    return x.d>y.d;
}

struct tree
{
    int l,r;
    LL sum1,sum2;
}nil[10004000];

int n,m;
int root[N],cnt;
LL g,L;

void update(int &ro,int l,int r,int p,LL ad1,LL ad2)
{
    nil[++cnt]=nil[ro];
    ro=cnt;
    nil[ro].sum1+=ad1;
    nil[ro].sum2+=ad2;

    if(l==r)
    return;

    int mid=(l+r)/2;
    if(p<=mid)
    update(nil[ro].l,l,mid,p,ad1,ad2);
    else
    update(nil[ro].r,mid+1,r,p,ad1,ad2);
}

LL work(int ro)
{
    if(nil[ro].sum1<L)
    return oo;

    int l=1,r=100000;
    LL tot1=0,tot2=0;
    while(l!=r)
    {
        int mid=(l+r)/2;
        if(nil[nil[ro].l].sum1+tot1>=L)
        {
            r=mid;
            ro=nil[ro].l;
        }
        else
        {
            tot1+=nil[nil[ro].l].sum1;
            tot2+=nil[nil[ro].l].sum2;
            l=mid+1;
            ro=nil[ro].r;
        }
    }
    return tot2+(L-tot1)*l;
}

int main()
{
    scanf("%d%d",&n,&m);

    int hh=0;

    for(int i=1;i<=n;i++)
    scanf("%d%d%d",&f[i].d,&f[i].p,&f[i].l),hh=max(hh,f[i].d);

    int hy=hh;

    sort(f+1,f+n+1,cmp);

    for(int i=1;i<=n;i++)
    {
        while(hh>f[i].d)
        {
            cnt++;
            nil[cnt]=nil[root[hh]];
            root[hh-1]=cnt;
            hh--;
        }
        update(root[hh],1,100000,f[i].p,f[i].l,(LL)f[i].p*f[i].l);
    }

    while(hh>1)
    {
        cnt++;
        nil[cnt]=nil[root[hh]];
        root[hh-1]=cnt;
        hh--;
    }

    while(m--)
    {
        scanf("%lld%lld",&g,&L);
        if(work(root[1])>g)
        {
            printf("-1\n");
            continue;
        }
        int l=1,r=hy+1;
        while(l+1<r)
        {
            int mid=(l+r)/2;
            if(work(root[mid])<=g)
            l=mid;
            else
            r=mid;
        }
        printf("%d\n",l);
    }

    return 0;
}
阅读更多
版权声明:虽说本文就是在吹B,但转载也要标明出处哦 https://blog.csdn.net/q582116859/article/details/80355935
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

洛谷4602:混合果汁(可持久化线段树+二分)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭