首页 > 其他 > 详细

「主席树」[Ctsc2018]混合果汁

时间:2019-09-10 09:30:33      阅读:48      评论:0      收藏:0      [点我收藏+]

[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\n", juice[ans].d);
    }
    return 0;
}

「主席树」[Ctsc2018]混合果汁

原文:https://www.cnblogs.com/Nicoppa/p/11495431.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!