BZOJ5343[CTSC2018]混合果汁(二分答案+主席树)

题目链接

BZOJ

洛谷

解析


果然改了题还是写一下题解影响深刻啊,之前互测还做过加强版,结果今天还是没写出来……


显然可以二分答案,问题在于快速判断是否可行

把所有果汁按美味度由大到小排序后,只能选择\(mid\)左边的

从价格最小的开始选一定最优,所以我们可以以价格为下标构建线段树,维护总花费和总数量,在线段树上查找花费一定时最大数量即可

题目有多组询问,但果汁的顺序不变,可以主席树维护

注意判断数量不够的情况

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 100005

typedef long long LL;
struct ChairmanTree {
    struct Node {
        Node *ls, *rs;
        LL cost, amount;
    } * root[MAXN];
    void build();
    void update(Node *, Node *, int, int, int, LL);
    LL query(Node *, int, int, LL);
};
struct Juice {
    int deli, price, amount;
    bool operator <(const Juice &j) const { return deli > j.deli; }
};

int N, M;
Juice juice[MAXN];
ChairmanTree tr;

char gc();
LL read();

int main() {
    N = read(), M = read();
    for (int i = 1; i <= N; ++i) {
        juice[i].deli = read();
        juice[i].price = read();
        juice[i].amount = read();
    }
    std::sort(juice + 1, juice + N + 1);
    tr.build();
    while (M--) {
        LL money = read(), demand = read();
        int l = 1, r = N;
        while (l < r) {
            int mid = (l + r) >> 1;
            LL least = tr.query(tr.root[mid], 1, 100000, demand);
            if ((~least) &&least <= money) r = mid;
            else l = mid + 1;
        }
        LL least = tr.query(tr.root[l], 1, 100000, demand);
        if ((~least) && least <= money) printf("%d\n", juice[l].deli);
        else puts("-1");
    }
    
    return 0;
}
inline char gc() {
    static char buf[1000000], *p1, *p2;
    if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
    return p1 == p2 ? EOF : *p2++;
}
inline LL read() {
    LL res = 0; char ch = gc();
    while (ch < '0' || ch > '9') ch = gc();
    while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc();
    return res;
}
void ChairmanTree::build() {
    for (int i = 1; i <= N; ++i) update(root[i - 1], root[i] = new Node(), 1, 100000, juice[i].price, juice[i].amount);
}
void ChairmanTree::update(Node *pre, Node *cur, int L, int R, int pos, LL val) {
    if (L == R) cur->amount = (pre ? pre->amount : 0) + val, cur->cost = (pre ? pre->cost : 0) + val * pos;
    else {
        int mid = (L + R) >> 1;
        if (pos <= mid) {
            cur->rs = (pre ? pre->rs : 0);
            update(pre ? pre->ls : 0, cur->ls = new Node(), L, mid, pos, val);
        } else {
            cur->ls = (pre ? pre->ls : 0);
            update(pre ? pre->rs : 0, cur->rs = new Node(), mid + 1, R, pos, val);
        }
        cur->amount = (cur->ls ? cur->ls->amount : 0) + (cur->rs ? cur->rs->amount : 0);
        cur->cost = (cur->ls ? cur->ls->cost : 0) + (cur->rs ? cur->rs->cost : 0);
    }
}
LL ChairmanTree::query(Node *rt, int L, int R, LL rest) {
    if (!rt || rt->amount < rest) return -1;
    if (L == R) return L * rest;
    int mid = (L + R) >> 1;
    LL amt = (rt->ls ? rt->ls->amount : 0), cst = (rt->ls ? rt->ls->cost : 0);
    if (amt >= rest) return query(rt->ls, L, mid, rest);
    else return cst + query(rt->rs, mid + 1, R, rest - amt);
}
//Rhein_E

猜你喜欢

转载自www.cnblogs.com/Rhein-E/p/10651543.html