zoukankan      html  css  js  c++  java
  • 洛谷P4602 [CTSC2018]混合果汁(主席树)

    题目描述

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

    商店里有 nn 种果汁,编号为 0,1,cdots,n-10,1,,n1 。 ii 号果汁的美味度是 d_idi ,每升价格为 p_ipi 。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中, ii 号果汁最多只能添加 l_ili 升。

    现在有 mm 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 jj 个小朋友希望他得到的混合果汁总价格不大于 g_jgj ,体积不小于 L_jLj 。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。

    输入输出格式

    输入格式:

    输入第一行包含两个正整数 n, mn,m ,表示果汁的种数和小朋友的数量。接下来 nn 行,每行三个正整数 d_i, p_i, l_idi,pi,li ,表示 ii 号果汁的美味度为 d_idi ,每升价格为 p_ipi ,在一瓶果汁中的添加上限为 l_ili 。

    接下来 mm 行依次描述所有小朋友:每行两个数正整数 g_j, L_jgj,Lj 描述一个小朋友,表示他最多能支付 g_jgj 元钱,他想要至少 L_jLj 升果汁。

    输出格式:

    对于所有小朋友依次输出:对于每个小朋友,输出一行,包含一个整数,表示他能喝到的最美味的混合果汁的美味度。如果无法满足他的需求,则输出 -11 。

    输入输出样例

    输入样例#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 le 100000n,m100000 , 1 le d_i,p_i,l_i le 10^5, 1 le g_j, L_j le 10^{18}1di,pi,li105,1gj,Lj1018 。

    首先二分一波美味度

    然后我们需要在美味度大于当前值的果汁中取,很明显是价格越小的越先取到

    但是直接这样做复杂度是$O(n^2log^2n)$的

    对于任意一个美味度,我们可以把它能取得的价格用线段树维护

    然后可持久化一下就好了

    时间复杂度$O(nlog^2n)$

    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    const int MAXN = 2 * 1e6 + 10;
    inline int read() {
        char c = getchar(); int x = 0, f = 1; 
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M;
    int root[MAXN];
    struct Juice {
        int D, P, L;
        bool operator < (const Juice &rhs) const{
            return D < rhs.D;
        }
    }a[MAXN];
    struct node {
        int ls, rs, tj, mon;
    }T[MAXN];
    int limit = 0, tot = 0;
    #define ls(x) T[x].ls
    #define rs(x) T[x].rs
    int insert(int &now, int pre, int l, int r, int pos, int val) {
        now = ++tot;
        T[now].ls = T[pre].ls; T[now].rs = T[pre].rs; T[now].tj = T[pre].tj + val, T[now].mon = T[pre].mon + val * pos;
        if(l == r) return now;
        int mid = (l + r) >> 1;
        if(pos <= mid) T[now].ls = insert(T[now].ls, T[pre].ls, l, mid, pos, val);
        else            T[now].rs = insert(T[now].rs, T[pre].rs, mid + 1, r, pos, val);
        return now;
    }
    int Query(int now, int pre, int l, int r, int money) {
        if(l == r) {return min(money / l, T[now].tj - T[pre].tj);}     
        int used = T[ls(now)].mon - T[ls(pre)].mon, mid = l + r >> 1;
        if(used <= money) 
            return Query(rs(now), rs(pre), mid + 1, r, money - used) + T[ls(now)].tj - T[ls(pre)].tj;
        else 
            return Query(ls(now), ls(pre), l, mid, money);
    }
    int check(int pos, int G, int L) {
        int ans = Query(root[N], root[pos - 1], 0, limit, G);
        return ans >= L;
    }
    int Solve(int G, int L) {
        int l = 1, r = N, ans = 0;
        while(l <= r) {
            int mid = l + r >> 1;
            if(check(mid, G, L)) ans = mid, l = mid + 1;
            else r = mid - 1;
        }
        return ans == 0 ? -1 : a[ans].D;
    }
    main() {
        #ifdef WIN32
        freopen("a.in", "r", stdin);
        #endif
        N = read(), M = read();
        for(int i = 1; i <= N; i++)
            a[i].D = read(), a[i].P = read(), a[i].L = read(), limit = max(a[i].P, limit);
        sort(a + 1, a + N + 1);
        for(int i = 1; i <= N; i++) 
            insert(root[i], root[i - 1], 0, limit, a[i].P, a[i].L);
        while(M--) {
            int G = read(), L = read();
            printf("%lld
    ", Solve(G, L));
        }
    }
  • 相关阅读:
    把Chrome浏览器变成文本编辑器
    pigcms 标签读不出
    全排列函数
    线性基(二
    线性基(一
    fabs() abs()
    字面量声明的函数,后边最好加一个分号,否则的话,在控制台执行有问题的
    mongo集群
    linux的查找命令
    mysql 解决Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’错误
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9059604.html
Copyright © 2011-2022 走看看