zoukankan      html  css  js  c++  java
  • 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
    ", 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
    
  • 相关阅读:
    Menu-actionBarMenu字体颜色修改
    actionBarTab-actionBarTab自定义 布局没法改变其中字体相对中间的位置
    Funui-overlay 如何添加theme 的 overlay
    java进阶——反射(Reflect)
    java工具类学习整理——集合
    Java实例练习——java实现自动生成长度为10以内的随机字符串(可用于生成随机密码)
    打通Java与MySQL的桥梁——jdbc
    SQL数据库操作整理
    PhpStorm 4.0 & 5.0 部署本地Web应用
    PhpStorm 4.0 & 5.0 部署本地Web应用
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10651543.html
Copyright © 2011-2022 走看看