BZOJ5343[CTSC2018]混合果汁(二分答案+主席树)
题目链接
解析
果然改了题还是写一下题解影响深刻啊,之前互测还做过加强版,结果今天还是没写出来……
显然可以二分答案,问题在于快速判断是否可行
把所有果汁按美味度由大到小排序后,只能选择\(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