1. 程式人生 > >[Luogu P4602] [BZOJ 5343] [CTSC2018]混合果汁

[Luogu P4602] [BZOJ 5343] [CTSC2018]混合果汁

洛谷傳送門

BZOJ傳送門

題目描述

小 R 熱衷於做黑暗料理,尤其是混合果汁。

商店裡有 n n 種果汁,編號為 0 , 1 ,

  , n 1 0,1,\cdots,n-1 i i
號果汁的美味度是 d i d_i ,每升價格為 p i
p_i
。小 R 在製作混合果汁時,還有一些特殊的規定,即在一瓶混合果汁中, i i 號果汁最多隻能新增 l i l_i 升。

現在有 m m 個小朋友過來找小 R 要混合果汁喝,他們都希望小 R 用商店裡的果汁製作成一瓶混合果汁。其中,第 j j 個小朋友希望他得到的混合果汁總價格不大於 g j g_j ,體積不小於 L j L_j 。在上述這些限制條件下,小朋友們還希望混合果汁的美味度儘可能地高,一瓶混合果汁的美味度等於所有參與混合的果汁的美味度的最小值。請你計算每個小朋友能喝到的最美味的混合果汁的美味度。

輸入輸出格式

輸入格式:

輸入第一行包含兩個正整數 n , m n, m ,表示果汁的種數和小朋友的數量。接下來 n n 行,每行三個正整數 d i , p i , l i d_i, p_i, l_i ,表示 i i 號果汁的美味度為 d i d_i ,每升價格為 p i p_i ,在一瓶果汁中的新增上限為 l i l_i

接下來 m m 行依次描述所有小朋友:每行兩個數正整數 g j , L j g_j, L_j 描述一個小朋友,表示他最多能支付 g j g_j 元錢,他想要至少 L j L_j 升果汁。

輸出格式:

對於所有小朋友依次輸出:對於每個小朋友,輸出一行,包含一個整數,表示他能喝到的最美味的混合果汁的美味度。如果無法滿足他的需求,則輸出 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 1 d i , p i , l i 1 0 5 1 \le d_i,p_i,l_i \le 10^5 , 1 g j , L j 1 0 18 1 \le g_j, L_j \le 10^{18}

測試點編號 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
13,14,15 100000 100000 l i = 1 l_i=1
16,17,18,19,20 100000 100000

解題分析

一開始想用整體二分搞, 然後發現似乎複雜度不太對, 只好用主席樹。

具體而言, 先預處理出從大到小 d i \ge d_i 美味度的飲品各個價格和花費的總和, 用線段樹維護這個花費和和總量, 線段樹每個葉節點表示單價離散化出來為第 k k 小的飲品的數量和總花費。 這樣處理後每個詢問我們二分答案, 貪心取便宜的就好。

總複雜度 O ( N l o g 2 ( N ) ) O(Nlog^2(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]