zoukankan      html  css  js  c++  java
  • 「主席树」[Ctsc2018]混合果汁

    [Ctsc2018]混合果汁

    题目链接:混合果汁

    这道题增强了我对二分和主席树的认识,很好的一道题

    终于开始认真学OI了,还是比较上瘾 开始刷bzoj 刷刷刷

    题目大意

    每次给你三个信息,表示一瓶果汁的价值量(d)、每升价格(p)、一瓶饮料中最多添加多少升(l)

    然后需要一瓶混合果汁,每次给你这瓶混合果汁的限制条件(G)(L),分别代表最多能支付的钱和至少多少升饮料,然后这瓶果汁的价值要尽可能的大,每瓶混合果汁的价值为所有加进去的果汁的价值量的最小值。

    题目题解

    我觉得比较水的一道题,但是不看下题解还真的写不出

    正好学了主席树,听zbww介绍写的一道题,看了下题没看懂,再看了一遍,一瓶混合果汁的最小值是由某一瓶果汁的价值量来定的,那么我们可以根据价值量进行从小到大的排序,然后再发现,每次会有两个限制条件(G)(L),看了题解发现可以用二分判定来搞,那怎么很快的维护判断(G)(L)?很显然对于单独数据可以在权值线段树上来进行,但是这样就会导致一个问题,我们之前二分的(d)就不能加入判断当中了,因为二分的(d)一直在变,而我们的权值线段树却不能一直变,而且对于每组数据(d)可能重复,哎?重复,这不就跟历史版本一样吗,很明显我们就得到了主席树(可持久化线段树)这样一个算法来维护判断(G, L),和求第(k)大一样即可

    那这样我们就可以得到代码

    /**************************************************************
        Problem: 5343
        User: Nicoppa
        Language: C++
        Result: Accepted
        Time:15712 ms
        Memory:104428 kb
    ****************************************************************/
     
    //#define fre yes
     
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define int long long
    //草 要开longlong 不开只有30
    const int N = 100005;
    struct Other {
        int d, p, l;
    } juice[N];
    struct Node {
        int l, r, w, lis;
    } tree[N << 5];
    int T[N];
     
    bool cmp(Other x, Other y) {
        return x.d < y.d;
    } //对d排序
     
    int cnt;
    void build(int l, int r) {
        int rt = ++cnt;
        tree[rt].l = l;
        tree[rt].r = r;
        tree[rt].lis = tree[rt].w = 0;
        if(l == r) return ;
        int mid = (l + r) >> 1;
        build(l, mid);
        build(mid + 1, r);
    } //建个空树
     
    int update(int pre, int l, int r, int p, int lis) {
        int rt = ++cnt;
        tree[rt].l = tree[pre].l;
        tree[rt].r = tree[pre].r;
        tree[rt].w = tree[pre].w + p * lis;
        tree[rt].lis = tree[pre].lis + lis;
        if(l == r) return rt;
        int mid = (l + r) >> 1;
        if(mid >= p) tree[rt].l = update(tree[pre].l, l, mid, p, lis);
        else tree[rt].r = update(tree[pre].r, mid + 1, r, p, lis);
        return rt;
    } //更新每次版本
     
    int query(int u, int v, int l, int r, int k) {
        if(l == r) return l * k;
        int t = tree[tree[v].l].lis - tree[tree[u].l].lis;
        int mid = (l + r) >> 1;
        if(t >= k) return query(tree[u].l, tree[v].l, l, mid, k);
        else return tree[tree[v].l].w - tree[tree[u].l].w + query(tree[u].r, tree[v].r, mid + 1, r, k - t);
    } //查询
     
    signed main() {
        static int n, m, pMax;
        scanf("%lld %lld", &n, &m);
        for (int i = 1; i <= n; i++) {
            int d, p, l;
            scanf("%lld %lld %lld", &d, &p, &l);
            juice[i].d = d;
            juice[i].p = p;
            juice[i].l = l;
            pMax = std::max(pMax, p);
        } std::sort(juice + 1, juice + 1 + n, cmp);
     
        T[0] = 0;
        build(1, pMax);
        for (int i = 1; i <= n; i++) {
            T[i] = update(T[i - 1], 1, pMax, juice[i].p, juice[i].l);
        }
     
        for (int i = 1; i <= m; i++) {
            int g, lis;
            scanf("%lld %lld", &g, &lis);
            int l = 1, r = n, ans = -1;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(query(T[mid - 1], T[n], 1, pMax, lis) <= g && tree[T[n]].lis - tree[T[mid - 1]].lis >= lis) {
                    l = mid + 1; ans = mid;
                } else r = mid - 1;
            }
     
            if(ans == -1) puts("-1");
            else printf("%lld
    ", juice[ans].d);
        }
        return 0;
    }
    
  • 相关阅读:
    第04组 Beta冲刺(2/5)
    第04组 Beta冲刺(1/5)
    第04组 Alpha事后诸葛亮
    第04组 Alpha冲刺(6/6)
    第04组 Alpha冲刺(5/6)
    第04组 Alpha冲刺(4/6)
    第04组 Alpha冲刺(3/6)
    作业2-1:矩阵协方差
    作业lab1-1:lammps教程总结
    如何在服务器上传/下载文件
  • 原文地址:https://www.cnblogs.com/Nicoppa/p/11495431.html
Copyright © 2011-2022 走看看