2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)
2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)
https://www.luogu.com.cn/problem/P1848
题意:
当农夫约翰闲的没事干的时候,他喜欢坐下来看书。多年过去,他已经收集了 N 本书 (1 <= N <= 100,000), 他想造一个新的书架来装所有书。
每本书 i 都有宽度 W(i) 和高度 H(i)。书需要按顺序添加到一组书架上;比如说,第一层架子应该包含书籍1 ... k,第二层架子应该以第k + 1本书开始,以下如此。每层架子的总宽度最大为L(1≤L≤1,000,000,000)。每层的高度等于该层上最高的书的高度,并且整个书架的高度是所有层的高度的总和,因为它们都垂直堆叠。
请帮助农夫约翰计算整个书架的最小可能高度。
有N(1 <= N <= 100000)本书,每本书有一个宽度W(i),高度H(i),(1 <= H(i) <= 1,000,000; 1 <= W(i) <= L)。
现在有足够多的书架,书架宽度最多是L (1 <= L <= 1,000,000,000),把书按顺序(先放1,再放2.....)放入书架。某个书架的高度是该书架中所放的最高的书的高度。
将所有书放入书架后,求所有书架的高度和的最小值?
分析:
对于前 \(i\) 本书放在书架上需要的高度为 \(f_i\) 。
设 \(sum_i\) 为前 \(i\) 本书宽度 \(w_j(j\in j<=i)\) 之和,则
j\in sum_i-sum_{j-1}<=L
\]
对于第 \(i\) 本书,存在 \(pos_i\) 使得 \(pos_i\) 是 \(i\) 最左侧的一本书满足 \(h_{pos_i}>=h_i\) 。对于第 \(pos_i+1\) 本书到到第 \(i\) 本书之间最大值为 \(h_i\) 。
建一棵线段树,可区间修改(修改 \(pos_i+1\) 到 \(i\) 的值为 \(h_i\) )、区间查询(查询 \(j\) 到 \(i\) 之间 \(f_{j-1}+\max(f_{j},f_{j+1},\cdots,f_i)\) 最小值)、单点修改(对于每个点要初始化)。
初始化的时候对于每个点 \(i\) ,因为必须要满足 \(i\) 前所有点依旧满足条件,所以每个叶子结点的含义就是以 \(i\) 为分界点,\(f_{i-1}+\max(f_i,f_{i+1},\cdots,f_{要查询的点})\) ,而且每次更新的区间的值为 \(h_i\) ,这个值会不断覆盖以前更新过的值,但是保证最优因为被更新的区间的值都比 \(h_i\) 小,且不存在 \(j\) 满足 \(h_j>h_i\) 且 \(pos_i+1<=j<=i\) 。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define int long long
typedef long long ll;
const ll inf=1e18;
const int N=1e5+10;
int n,L,h[N],w[N],pos[N],sum[N];
ll f[N],lazy[N<<2],val[N<<2],tot[N<<2];
stack<int>s;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
s=s*10+ch-'0';
ch=getchar();
}
return s*w;
}
inline void update(int x){
tot[x]=min(tot[x<<1],tot[x<<1|1]);
val[x]=min(val[x<<1],val[x<<1|1]);
}
inline void pushdown(int x){
if(lazy[x]==inf)return ;
tot[x<<1]=val[x<<1]+lazy[x];
tot[x<<1|1]=val[x<<1|1]+lazy[x];
lazy[x<<1]=lazy[x<<1|1]=lazy[x];
lazy[x]=inf;
}
inline void build(int x,int l,int r){
tot[x]=val[x]=lazy[x]=inf;
if(l==r)return ;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
inline void changeline(int x,int l,int r,int L,int R,int k){
if(l>R||r<L)return ;
if(l>=L&&r<=R)return (void)(tot[x]=val[x]+k,lazy[x]=k);
pushdown(x);
int mid=(l+r)>>1;
if(mid>=L)changeline(x<<1,l,mid,L,R,k);
if(R>mid)changeline(x<<1|1,mid+1,r,L,R,k);
update(x);
}
inline void changespot(int x,int l,int r,int k){
if(l==r)return (void)(tot[x]=inf,val[x]=f[l-1]);
pushdown(x);
int mid=(l+r)>>1;
if(k<=mid)changespot(x<<1,l,mid,k);
if(k>mid)changespot(x<<1|1,mid+1,r,k);
update(x);
}
inline ll query(int x,int l,int r,int L,int R){
if(l>R||r<L)return inf;
if(l>=L&&r<=R)return tot[x];
pushdown(x);
int mid=(l+r)>>1;
ll ans=inf;
if(L<=mid)ans=min(ans,query(x<<1,l,mid,L,R));
if(R>mid)ans=min(ans,query(x<<1|1,mid+1,r,L,R));
return ans;
}
signed main(){
n=read();L=read();
for(int i=1;i<=n;i++)h[i]=read(),w[i]=read(),sum[i]=sum[i-1]+w[i];
s.push(1);
for(int i=2;i<=n;i++){
while(!s.empty()&&h[i]>h[s.top()])s.pop();
if(!s.empty())pos[i]=s.top();
s.push(i);
}
build(1,1,n);
for(int i=1;i<=n;i++){
changespot(1,1,n,i);
if(pos[i]<i)changeline(1,1,n,pos[i]+1,i,h[i]);
int Li=lower_bound(sum,sum+i+1,sum[i]-L)-sum;
int Ri=i;
if(Li<Ri)f[i]=query(1,1,n,Li+1,Ri);
}
cout<<f[n];
return 0;
}
2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)的更多相关文章
- 2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串)
2021.12.09 [HEOI2016/TJOI2016]排序(线段树+二分,把一个序列转换为01串) https://www.luogu.com.cn/problem/P2824 题意: 在 20 ...
- 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点
容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...
- Codeforces 1603D - Artistic Partition(莫反+线段树优化 dp)
Codeforces 题面传送门 & 洛谷题面传送门 学 whk 时比较无聊开了道题做做发现是道神题( 介绍一种不太一样的做法,不观察出决策单调性也可以做. 首先一个很 trivial 的 o ...
- Codeforces Round #426 (Div. 2) D 线段树优化dp
D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...
- BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】
BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...
- [AGC011F] Train Service Planning [线段树优化dp+思维]
思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...
- 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp
题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...
- POJ 2376 Cleaning Shifts (线段树优化DP)
题目大意:给你很多条线段,开头结尾是$[l,r]$,让你覆盖整个区间$[1,T]$,求最少的线段数 题目传送门 线段树优化$DP$裸题.. 先去掉所有能被其他线段包含的线段,这种线段一定不在最优解里 ...
- 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$
正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...
随机推荐
- 内网穿透工具--NPS
一.简介 NPS是一款轻量级,高性能,强大功能的内网穿透代理服务器.目前支持TCP,UDP流量转发,可支持任何TCP,UDP上层协议(访问内网网站,本地支付接口调试,SSH访问,远程桌面,内网dns解 ...
- Android 12(S) 图形显示系统 - Surface 一点补充知识(十二)
必读: Android 12(S) 图形显示系统 - 开篇 一.前言 因为个人工作主要是Android多媒体播放的内容,在工作中查看源码或设计程序经常会遇到调用API: static inline i ...
- synchronized底层实现原理及锁优化
一.概述 1.synchronized作用 原子性:synchronized保证语句块内操作是原子的 可见性:synchronized保证可见性(通过"在执行unlock之前,必须先把此变量 ...
- SQL 语言包括哪几部分?每部分都有哪些操作关键字?
SQL 语言包括数据定义(DDL).数据操纵(DML),数据控制(DCL)和数据查询(DQL) 四个部分. 数据定义:Create Table,Alter Table,Drop Table, Crae ...
- MySQL 根据JSON类型的字段进行过滤数据的方式
第一种方式:JSON_CONTAINS 函数 : 执行相等形式的比较 注意:值的类型一定要相同,不然会报错 文档地址:https://dev.mysql.com/doc/refman/8.0/en/j ...
- Kafka 判断一个节点是否还活着有那两个条件?
(1)节点必须可以维护和 ZooKeeper 的连接,Zookeeper 通过心跳机制检查每 个节点的连接 (2)如果节点是个 follower,他必须能及时的同步 leader 的写操作,延时不能太 ...
- 说说 Redis 哈希槽的概念?
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽, 集群的每个节点 ...
- Java 中如何格式化一个日期?如格式化为 ddMMyyyy 的形式?
Java 中,可以使用 SimpleDateFormat 类或者 joda-time 库来格式日期. DateFormat 类允许你使用多种流行的格式来格式化日期.参见答案中的示例代 码,代码中演示了 ...
- 学习MFS(四)
一.搭建Master Server 1.安装相关编译器.工具包 [root@master ~]# yum -y install gcc gcc-c++ zlib-devel 2.创建进程用户 [roo ...
- C语言之关键字(知识点2)
关键字又叫保留字,这些关键字不可以再次定义 解析