• [洛谷P4602] CTSC2018 混合果汁


    问题描述

    小 R 热衷于做黑暗料理,尤其是混合果汁。 商店里有 n 种果汁,编号为 0, 1, 2, . . . , n − 1。i 号果汁的美味度是 di,每升价格为 pi。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中,i 号果汁最 多只能添加 li 升。 现在有 m 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁 制作成一瓶混合果汁。其中,第 j 个小朋友希望他得到的混合果汁总价格不大于 gj,体 积不小于 Lj。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高, 一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小 朋友能喝到的最美味的混合果汁的美味度。

    输入格式

    从文件 juice.in 中读入数据。

    输入第一行包含两个正整数 n, m,表示果汁的种数和小朋友的数量。

    接下来 n 行,每行三个正整数 di , pi , li,表示 i 号果汁的美味度为 di,每升价格为 pi,在一瓶果汁中的添加上限为 li。

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

    输出格式

    输出到文件 juice.out 中。

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

    样例输入

    3 4
    1 3 5
    2 1 3
    3 2 5
    6 3
    5 3
    10 10
    20 10

    样例输出

    3
    2
    -1
    1

    说明

    对于所有的测试数据,保证 n, m ≤ 100000,1 ≤ di , pi , li ≤ 10^5,1 ≤ gj , Lj ≤ 10^18。

    解析

    通过打表等一系列玄学方式可以发现答案具有单调性。二分一个d,则我们只能选择大于等于d的果汁。然后对所有大于等于d的果汁建立一棵以价格为下标的权值线段树,每个节点还要保存一下总体积和价格。这样我们就可以在权值线段树上用Lim二分了。

    但是不能每二分一次就重新建树。我们可以建立一棵主席树利用可持久化来解决这个问题。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    #define N 100002
    #define T 100000
    using namespace std;
    struct ChairmanTree{
    	int l,r,suml,sump;
    }t[N*40];
    struct juice{
    	int d,p,l;
    }a[N];
    int n,m,i,g[N],L[N],root[N],p;
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    int my_comp(const juice &x,const juice &y)
    {
    	return x.d<y.d;
    }
    int insert(int pre,int l,int r,int L,int P)
    {
    	p++;
    	int num=p;
    	t[p]=t[pre];
    	t[p].suml+=L;t[p].sump+=L*P;
    	if(l<r){
    		int mid=(l+r)/2;
    		if(P<=mid) t[p].l=insert(t[pre].l,l,mid,L,P);
    		else t[p].r=insert(t[pre].r,mid+1,r,L,P);
    	}
    	return num;
    }
    int ask(int p,int l,int r,int L)
    {
    	if(l==r) return l*L;
    	int mid=(l+r)/2;
    	if(L<=t[t[p].l].suml) return ask(t[p].l,l,mid,L);
    	return t[t[p].l].sump+ask(t[p].r,mid+1,r,L-t[t[p].l].suml);
    }
    signed main()
    {
    	n=read();m=read();
    	for(i=1;i<=n;i++) a[i].d=read(),a[i].p=read(),a[i].l=read();
    	for(i=1;i<=m;i++) g[i]=read(),L[i]=read();
    	a[0].d=-1;
    	sort(a+1,a+n+1,my_comp);
    	for(i=n;i>=1;i--) root[i]=insert(root[i+1],1,T,a[i].l,a[i].p);
    	for(i=1;i<=m;i++){
    		int l=1,r=T,mid,ans=0;
    		while(l<=r){
    			mid=(l+r)/2;
    			if(L[i]<=t[root[mid]].suml&&ask(root[mid],1,T,L[i])<=g[i]){
    				ans=mid;
    				l=mid+1;
    			}
    			else r=mid-1;
    		}
    		printf("%lld
    ",a[ans].d);
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue 部署到服务器
    半小时学会 Vuex 数据共享
    Vue 第一次安装 经历 vue cli 3.0
    第一次使用视频截图 ant design
    Luckysheet
    关于导出--分页
    ADO.net很重要
    委托到底是什么? (转载)
    生成流水单号
    Ext.NET 基础学习笔记07 (GridPanel用法)
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11878957.html
Copyright © 2020-2023  润新知