BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流
题目链接:
题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量),每卖出一个单位的蔬菜获得收益为$a_{i}$,第一次卖出一种蔬菜会得到$s_{i}$的额外收益,限制每天最多卖出$m$个单位的蔬菜,有$k$次询问,每次询问卖$p_{i}$天的最大收益。
因为每种蔬菜坏掉的部分是固定的,那么我们可以将每种蔬菜分成$\frac{c_{i}-1}{x_{i}}+1$类,第$i$类在第$i$天坏掉。那么对于本题就可以建出费用流模型:源点向每一天连边,容量为$m$,费用为$0$;第$i$天向第$i+1$天连边,容量为$INF$,费用为$0$;每一天向每种蔬菜这一天坏掉的那类连边,容量为这一类的数量,费用为$0$;每一类蔬菜向汇点连边,容量为这一类的数量,费用为$a_{i}$。最后在最后一天每一种蔬菜中取出一个容量新建一个点连向汇点,容量为$1$,费用为$a_{i}+s_{i}$。这样直接跑费用流会有$60pts$。我们观察一下这个图的特殊性质:只有蔬菜向汇点连的边有费用。因为每次增广一定是选取最长路,那么每次增广的路径就一定不会走有费用的反向边(即不会退流)。这也就说明对于$p=i$时选取的蔬菜一定是$p=i-1$时选取的蔬菜的父集(多选的那部分就是最便宜的那$m$个蔬菜)。那么我们可以模拟这个费用流的过程——每次选择当前能选的蔬菜中权值最大的。为了使当前的选择是可行的,设$f[i]$为在第$i$天及之前过期的蔬菜选取量,那么我们就要保证$\forall i,f[i]-i*m<=0$,即$max(f[i]-i*m)<=0$,这个东西我们用线段树来维护即可。那么我们现在的问题就是如何要让当前权值最大的蔬菜尽可能的多选,因为选择第$i$天过期的蔬菜会将所有$i\le j$的$f[j]$都$+1$。那么如果不能选后过期的就一定不能选先过期的,而不能选先过期的可能还能选后过期的,所以我们每次贪心地先选后过期的那部分。如果一次选择使$masx(f[i]-i*m)>0$,说明这种蔬菜剩下的都过期了,那么就撤销这次操作并在以后都不选这种蔬菜。那么我们只要用堆维护所有种类的蔬菜然后从第一天开始,每天贪心地选$m$个蔬菜并记录每天的答案在最后统一输出即可。特别注意$x_{i}=0$的蔬菜看作都在最后一天过期。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define pr pair<int,int>
#define lim 100010
using namespace std;
int c[100010];
int a[100010];
int s[100010];
int x[100010];
int n,m,k,z;
ll ans[100020];
priority_queue<pr>q;
int mx[400010];
int sum[400010];
ll res;
void pushup(int rt)
{
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt)
{
if(sum[rt])
{
sum[rt<<1]+=sum[rt];
sum[rt<<1|1]+=sum[rt];
mx[rt<<1]+=sum[rt];
mx[rt<<1|1]+=sum[rt];
sum[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
mx[rt]=-l*m;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
mx[rt]+=v;
sum[rt]+=v;
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
{
change(rt<<1,l,mid,L,R,v);
}
if(R>mid)
{
change(rt<<1|1,mid+1,r,L,R,v);
}
pushup(rt);
}
bool judge(int id)
{
int t=x[id]?(c[id]-1)/x[id]+1:lim;
change(1,1,lim,t,lim,1);
if(mx[1]<=0)
{
return 1;
}
change(1,1,lim,t,lim,-1);
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i],&s[i],&c[i],&x[i]);
q.push(make_pair(a[i]+s[i],i));
}
build(1,1,lim);
for(int i=1;i<=lim;i++)
{
int num=m;
while(num&&!q.empty())
{
int v=q.top().first;
int id=q.top().second;
q.pop();
if(!judge(id))continue;
res+=v,num--,c[id]--;
if(c[id])
{
q.push(make_pair(a[id],id));
}
}
ans[i]=res;
}
while(k--)
{
scanf("%d",&z);
printf("%lld\n",ans[z]);
}
}
BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流的更多相关文章
- 【BZOJ3252】攻略 DFS序+线段树(模拟费用流)
[BZOJ3252]攻略 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛> ...
- BZOJ4977[Lydsy1708月赛]跳伞求生——贪心+堆+模拟费用流
题目链接: 跳伞求生 可以将题目转化成数轴上有$n$个人和$m$个房子,坐标分别为$a_{i}$和$b_{i}$,每个人可以进一个他左边的房子,每个房子只能进一个人.每个房子有一个收益$c_{i}$, ...
- [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流
题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...
- BZOJ4946 NOI2017蔬菜(贪心+堆)
容易想到一个费用流做法:将每种蔬菜拆成p种,对应p个过期时间,每一种向可以卖的时间连边,第一次卖的奖励算在最晚过期的一种里.对于天数动态加点.不过这样边数太多了,因为第i天能卖的第i-1天一定能卖,可 ...
- 模拟费用流 & 可撤销贪心
1. CF730I Olympiad in Programming and Sports 大意: $n$个人, 第$i$个人编程能力$a_i$, 运动能力$b_i$, 要选出$p$个组成编程队, $s ...
- 【CF280D】 k-Maximum Subsequence Sum ,线段树模拟费用流
昨天考试被教育了一波.为了学习一下\(T3\)的科技,我就找到了这个远古时期的\(cf\)题(虽然最后\(T3\)还是不会写吧\(QAQ\)) 顾名思义,这个题目其实可以建成一个费用流的模型.我们用流 ...
- Codeforces 280D k-Maximum Subsequence Sum [模拟费用流,线段树]
洛谷 Codeforces bzoj1,bzoj2 这可真是一道n倍经验题呢-- 思路 我首先想到了DP,然后矩阵,然后线段树,然后T飞-- 搜了题解之后发现是模拟费用流. 直接维护选k个子段时的最优 ...
- 【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)
[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交 ...
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
随机推荐
- Windows Community Toolkit 3.0 - UniformGrid
概述 UniformGrid 控件是一个响应式的布局控件,允许把 items 排列在一组均匀分布的行或列中,以填充整体的可用显示空间,形成均匀的多个网格.默认情况下,网格中的每个单元格大小相同. 这是 ...
- oracle树形结构层级查询之start with ....connect by prior、level、order by以及sys_connect_by_path之浅谈
浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...
- LNK2022: 元数据操作失败(8013118D): 重复类型(FactoryContext)中的布局信息不一致: (0x02000230)
1. c++项目 A 编译成A.lib文件 2. c++项目B引用这个A.lib文件 3. A项目存在一个类跟B项目一样,但是A项目其他文件需要这个类里面的某些东西,我将不需要的全部注释掉,然后编译A ...
- NewZealand。。。
秀个存在感...
- SQL 显示表名显示列名
显示表名:show 表名: 显示列(Field)名:show columns from 表名:
- python代码风格指南:pep8 中文版
本文档所提供的编码规范,适用于主要的Python发行版中组成标准库的Python代码.请参阅PEP关于Python的C实现的C编码风格指南的描述. 本文档和PEP257(文档字符串规范)改编自Guid ...
- HDU - 1540 线段树的合并
这个题题意我大概解释一下,就是一开始一条直线,上面的点全是联通的,有三种操作 1.操作D把从左往右第x个村庄摧毁,然后断开两边的联通. 2.询问Q节点相联通的最长长度 3.把最后破坏的村庄重建. 这个 ...
- c语言之sizeof的细节
关于sizeof,我们知道sizeof并不是一个函数,尽管通常我们会用sizeof()用法(这是c语言的坑),在此关于sizeof的一些关键不被认知的进行一下总结: # include "i ...
- elasticsearch数据输入和输出
Elastcisearch 是分布式的 文档 存储.它能存储和检索复杂的数据结构–序列化成为JSON文档–以 实时 的方式. 换句话说,一旦一个文档被存储在 Elasticsearch 中,它就是可以 ...
- 《梦断代码》Scott Rosenberg著(一)
两打程序员,3年时间,4732个bug,只为打造超卓软件. --序 在我们平时看到的大部分书籍只是讲技术和理论,但我们其实并不知道在真实的软件开发过程中,这些技术和理论究竟是被什么样的人如何去使用, ...