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
posted @ 2019-04-03 21:07  Rhein_E  阅读(139)  评论(0编辑  收藏  举报