洛谷传送门
BZOJ传送门
题目描述
小 R 热衷于做黑暗料理,尤其是混合果汁。
商店里有 n n n 种果汁,编号为 0 , 1 , ⋯   , n − 1 0,1,\cdots,n-1 0,1,⋯,n−1 。 i i i号果汁的美味度是 d i d_i di,每升价格为 p i p_i pi。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中, i i i 号果汁最多只能添加 l i l_i li 升。
现在有 m m m 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 j j j个小朋友希望他得到的混合果汁总价格不大于 g j g_j gj,体积不小于 L j L_j Lj。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。
输入输出格式
输入格式:
输入第一行包含两个正整数 n , m n, m n,m,表示果汁的种数和小朋友的数量。接下来 n n n 行,每行三个正整数 d i , p i , l i d_i, p_i, l_i di,pi,li,表示 i i i 号果汁的美味度为 d i d_i di,每升价格为 p i p_i pi,在一瓶果汁中的添加上限为 l i l_i li。
接下来 m m m 行依次描述所有小朋友:每行两个数正整数 g j , L j g_j, L_j gj,Lj 描述一个小朋友,表示他最多能支付 g j g_j gj 元钱,他想要至少 L j L_j Lj 升果汁。
输出格式:
对于所有小朋友依次输出:对于每个小朋友,输出一行,包含一个整数,表示他能喝到的最美味的混合果汁的美味度。如果无法满足他的需求,则输出 − 1 -1 −1。
输入输出样例
输入样例#1:
3 4
1 3 5
2 1 3
3 2 5
6 3
5 3
10 10
20 10
输出样例#1:
3
2
-1
1
说明
对于所有的测试数据,保证 n , m ≤ 100000 n, m \le 100000 n,m≤100000, 1 ≤ d i , p i , l i ≤ 1 0 5 1 \le d_i,p_i,l_i \le 10^5 1≤di,pi,li≤105, 1 ≤ g j , L j ≤ 1 0 18 1 \le g_j, L_j \le 10^{18} 1≤gj,Lj≤1018。
测试点编号 | n= | m= | 其他限制 |
---|---|---|---|
1,2,3 | 10 | 10 | 无 |
4,5,6 | 500 | 500 | 无 |
7,8,9 | 5000 | 5000 | 无 |
10,11,12 | 100000 | 100000 | p i = 1 p_i=1 pi=1 |
13,14,15 | 100000 | 100000 | l i = 1 l_i=1 li=1 |
16,17,18,19,20 | 100000 | 100000 | 无 |
解题分析
一开始想用整体二分搞, 然后发现似乎复杂度不太对, 只好用主席树。
具体而言, 先预处理出从大到小 ≥ d i \ge d_i ≥di美味度的饮品各个价格和花费的总和, 用线段树维护这个花费和和总量, 线段树每个叶节点表示单价离散化出来为第 k k k小的饮品的数量和总花费。 这样处理后每个询问我们二分答案, 贪心取便宜的就好。
总复杂度 O ( N l o g 2 ( N ) ) O(Nlog^2(N)) O(Nlog2(N))。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
#define ll long long
#define db double
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, m, cnt, dif;
int root[MX], id[MX], buf[MX];
struct Node {int son[2]; ll sum, tot;} tree[MX * 40];
struct INFO {ll cost, val, lim;} dat[MX];
IN bool operator < (const INFO &x, const INFO &y) {return x.val == y.val ? x.cost < y.cost : x.val > y.val;}
namespace PT
{
#define ls tree[now].son[0]
#define rs tree[now].son[1]
IN void pushup(R int now)
{
tree[now].tot = tree[ls].tot + tree[rs].tot;
tree[now].sum = tree[ls].sum + tree[rs].sum;
}
void insert(R int pre, int &now, R int lef, R int rig, R int tar, ll num)
{
now = ++cnt;
tree[now] = tree[pre];
if (lef == rig) return tree[now].tot += num, tree[now].sum += num * buf[tar], void();
int mid = lef + rig >> 1;
if (tar <= mid) insert(tree[pre].son[0], ls, lef, mid, tar, num);
else insert(tree[pre].son[1], rs, mid + 1, rig, tar, num);
pushup(now);
}
db query(R int now, R int lef, R int rig, db tar)
{
if (lef == rig) return min(1.0 * tree[now].tot, tar / buf[rig]);
int mid = lef + rig >> 1;
if (tree[ls].sum >= tar) return query(ls, lef, mid, tar);
else return query(rs, mid + 1, rig, tar - tree[ls].sum) + tree[ls].tot;
}
#undef ls
#undef rs
}
int main(void)
{
ll mon, lim; int lef, rig, ans, mid;
in(n), in(m);
for (R int i = 1; i <= n; ++i)
in(dat[i].val), in(dat[i].cost), in(dat[i].lim), buf[i] = dat[i].cost;
++n; dat[n].val = -1, dat[n].cost = 0, dat[n].lim = 1e18, buf[n] = dat[n].cost;
std::sort(dat + 1, dat + 1 + n);
std::sort(buf + 1, buf + 1 + n);
dif = std::unique(buf + 1, buf + 1 + n) - buf - 1;
for (R int i = 1; i <= n; ++i) id[i] = std::lower_bound(buf + 1, buf + 1 + dif, dat[i].cost) - buf;
for (R int i = 1; i <= n; ++i) PT::insert(root[i - 1], root[i], 1, dif, id[i], dat[i].lim);
W (m--)
{
in(mon), in(lim);
lef = 1, rig = n; db res;
W (lef <= rig)
{
mid = lef + rig >> 1;
if (res = PT::query(root[mid], 1, dif, mon) >= lim)
ans = mid, rig = mid - 1;
else lef = mid + 1;
}
printf("%d\n", dat[ans].val);
}
}