[BZOJ5343][Ctsc2018]混合果汁(二分+贪心+主席树)

Address

洛谷P4602
BZOJ5343
LOJ#2555

Solution

看到要最大化最小值,显然二分
先将所有的果汁按照美味度从大到小排序。
转化成判定性问题:在所有果汁的一个前缀 [ 1 , m i d ] [1,mid] 中,是否能选出一些果汁使得价格不超过 g g ,体积不小于 L L
显然,我们一定要让体积等于 L L ,并且要从单位价格低的果汁开始选。
把排序之后的果汁建成主席树,下标为单位价格。
主席树上存储体积之和以及价格之和。
可以在主席树上二分求得最小价格。
如果得到的最小价格不超过 g g ,那么向左调整。
否则向右调整。

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

typedef long long ll;

inline ll readll()
{
	ll res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 1e5 + 5, M = 3e6 + 5, MP = 1e5;
const ll INF = 2e18;

int n, m, ToT, rt[N];

struct edon
{
	int d, p, l;
} a[N];

struct node
{
	int lc, rc; ll sum, prc;
} T[M];

bool comp(edon a, edon b)
{
	return a.d > b.d;
}

void ins(int y, int &x, int l, int r, int p, ll add)
{
	T[x = ++ToT] = T[y];
	T[x].sum += add; T[x].prc += add * p;
	if (l == r) return;
	int mid = l + r >> 1;
	if (p <= mid) ins(T[y].lc, T[x].lc, l, mid, p, add);
	else ins(T[y].rc, T[x].rc, mid + 1, r, p, add);
}

ll ask(int x, int l, int r, ll lp)
{
	if (lp > T[x].sum) return INF;
	if (l == r) return lp * l;
	int mid = l + r >> 1;
	if (lp <= T[T[x].lc].sum) return ask(T[x].lc, l, mid, lp);
	else return ask(T[x].rc, mid + 1, r, lp - T[T[x].lc].sum)
		+ T[T[x].lc].prc;
}

int main()
{
	int i;
	ll g, L;
	n = read(); m = read();
	For (i, 1, n) a[i].d = read(), a[i].p = read(), a[i].l = read();
	std::sort(a + 1, a + n + 1, comp);
	For (i, 1, n) ins(rt[i - 1], rt[i], 1, MP, a[i].p, a[i].l);
	while (m--)
	{
		g = readll(); L = readll();
		int l = 1, r = n;
		while (l <= r)
		{
			int mid = l + r >> 1;
			if (ask(rt[mid], 1, MP, L) <= g) r = mid - 1;
			else l = mid + 1;
		}
		if (l == n + 1) puts("-1");
		else printf("%d\n", a[l].d);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/83216989