P1295 [TJOI2011]书架(线段树dp)

我好菜

先考虑普通dp: d p i = m i n ( d p j + m a x ( h j + 1 , h j + 2 … , h i ) ) dp_i=min(dp_j+max(h_{j+1},h_{j+2}\dots,h_i)) dpi​=min(dpj​+max(hj+1​,hj+2​…,hi​))

考虑对于向左找到第一个大于 h [ i ] h[i] h[i]的位置: p r e i pre_i prei​

则对于 [ p r e i + 1 , i ] [pre_i+1,i] [prei​+1,i] 的 m a x ( h j ) = h i max(h_j)=h_i max(hj​)=hi​

所以可以线段树维护区间的最小 f f f ,每次单调赋值 f i − 1 f_{i-1} fi−1​

和最小 f + h f+h f+h ,区间对 [ p r e i + 1 , i ] [pre_i+1,i] [prei​+1,i] 加 h h h

然后区间查询 [ p + 1 , i ] [p+1,i] [p+1,i]的最小 f + h f+h f+h 即可。

// Problem: P1295 [TJOI2011]书架
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1295
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-12-02 20:14:06
// --------by Herio--------#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = {402653189,805306457,1610612741,998244353};
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr)
void Print(int *a,int n){for(int i=1;i<n;i++)printf("%d ",a[i]);printf("%d\n",a[n]);
}
template <typename T>     //x=max(x,y)  x=min(x,y)
void cmx(T &x,T y){if(x<y) x=y;
}
template <typename T>
void cmn(T &x,T y){if(x>y) x=y;
}
//区间修改 区间求和
#define il inline
#define lx x<<1
#define rx x<<1|1
#define len(x) (a[x].r-a[x].l+1)
ll f[N];
struct SegTree{struct node{int l,r,lz;ll s,f;}a[N<<2];il void re(int x){a[x].s=min(a[lx].s,a[rx].s);a[x].f=min(a[lx].f,a[rx].f); }il void ptg(int x,int y){a[x].lz=y;a[x].s=a[x].f+y;}il void pd(int x){if(a[x].lz!=inf){ptg(lx,a[x].lz),ptg(rx,a[x].lz);a[x].lz=inf;}}il void bud(int x,int l,int r){a[x].l=l,a[x].r=r,a[x].s=a[x].f=a[x].lz=inf;if(l==r){//scanf("%d",&a[x].s);return;}int m=(l+r)>>1;bud(lx,l,m),bud(rx,m+1,r);re(x);}il void upd(int x,int l,int r,int val){if(a[x].l>=l&&a[x].r<=r){ptg(x,val);return;}pd(x);int m=(a[x].l+a[x].r)>>1;if(l<=m) upd(lx,l,r,val);if(r>m) upd(rx,l,r,val);re(x);}il void modfiy(int x,int p){if(a[x].l==a[x].r){a[x].s=inf,a[x].f=f[a[x].l-1];return;}pd(x);int m=(a[x].l+a[x].r)>>1;if(p<=m) modfiy(lx,p);else modfiy(rx,p);re(x);}il ll que(int x,int l,int r){if(a[x].l>=l&&a[x].r<=r) return a[x].s;pd(x);int m=(a[x].l+a[x].r)>>1;ll ans=inf;if(l<=m) ans=min(ans,que(lx,l,r));if(r>m) ans=min(ans,que(rx,l,r));return ans;}
}T;
int h[N];
ll s[N];
int pre[N];
int st[N],top;
int main(){int n,m;scanf("%d%d",&n,&m);rep(i,1,n){scanf("%d",&h[i]);s[i]=s[i-1]+h[i];}for(int i=1;i<=n;i++){while(top&&h[i]>h[st[top]]) top--;if(top) pre[i]=st[top];st[++top]=i;}  //Print(pre,n);T.bud(1,1,n);rep(i,1,n){T.modfiy(1,i);if(pre[i]+1<=i) T.upd(1,pre[i]+1,i,h[i]);int p=lower_bound(s,s+i+1,s[i]-m)-s;if(p<i) f[i]=T.que(1,p+1,i);//printf("f[%d]=%lld\n",i,f[i]);}printf("%lld\n",f[n]);return 0;
}

P1295 [TJOI2011]书架(线段树dp)相关推荐

  1. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  2. CodeForces - 1557D Ezzat and Grid(线段树+dp)

    题目链接:点击查看 题目大意:给出 nnn 个 010101 串,现在问最少需要删掉多少个串,才能使得剩下的串拼起来是连通的 规定两个 010101 串是连通的,当且仅当存在至少一列,在两个串中都为 ...

  3. CodeForces - 487B Strip(线段树+dp+二分)

    题目链接:点击查看 题目大意:给出一个长度为 n 的序列,现在要求分成尽可能少的子段,且每个子段需要满足: 最大值与最小值的差值小于等于 s 子段长度大于等于 l 题目分析:dp[ i ] 代表的是前 ...

  4. Educational Codeforces Round 81 (Rated for Div. 2) E. Permutation Separation 线段树 + dp

    传送门 文章目录 题意: 思路: 题意: 给你一个打乱的排列,每个位置都各有一个价值,让你选择一个分界点,分成p1,p2,...,prp_1,p_2,...,p_rp1​,p2​,...,pr​和pr ...

  5. Atcoder 077E - guruguru(线段树+dp)

    题目链接:http://arc077.contest.atcoder.jp/tasks/arc077_c 分析:如果某条线段包含x,显然应该先按一下到x,再从x走,反之必然是直接走过去,很容易想到用d ...

  6. POJ1769(线段树+DP)

    飞翔 题意 : 给定一个区间长度 n ,接下来给出 m 个子区间,要求最少选出多少个区间才能使得 1~n 这个区间被所选的所有子区间覆盖 分析: 首先是动态规划,dp[i]表示把最大值从1位置搞到第i ...

  7. Codeforces 1398 F. Controversial Rounds —— 线段树+dp

    This way 题意: 给你一个字符串,有些位置是已知的,有些是未知的,从位置1开始,如果有连续的0或者1大于等于k个,那么就算一轮游戏,然后0,1重新计数.问你当k=1~n的时候,游戏轮数最多是多 ...

  8. HDU 6447 YJJ's Salesman(线段树+DP)

    YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) T ...

  9. C2 - Pokémon Army (hard version)(思维+差分/线段树+dp)详解

    https://codeforces.com/contest/1420/problem/C2 这道题十分的锻炼思维,也让我知道了同样是差分,从前面减后面和从后面减前面是有不同的意义的. 还记得c1吗? ...

最新文章

  1. 前端基础--javascript 基础
  2. sql 语句 查询两个字段都相同的方法
  3. 清华大学车辆刚才专业大佬教你如何写SCI论文(转)
  4. 学习Java中遇到的问题积累_1
  5. 30万总奖金·垃圾分类挑战赛进入最后冲刺(附baseline完整分享)
  6. Net-DataGridView
  7. 并注册烧写钩子 获取启动介质类型_Spark Application的注册 源码剖析
  8. C#文件过滤器filter
  9. matlab替换矩阵中元素的值,怎么修改矩阵中的某些元素 或者简单点说保留矩阵中的元素...
  10. 4.1 手工编写第一个性能测试脚本
  11. 付款方对接银联入网仿真测试系统
  12. 谷歌chrome浏览器 抖动问题
  13. PTA 7-2 复数与基本类型的加减运算
  14. SQL优化13连问,收藏好!
  15. DOS命令:assoc
  16. pandas实例——电影数据分析
  17. django项目(天天生鲜电商项目)
  18. 【计算机基础-二进制的原码,反码,补码,真值】
  19. 《Delphi 版 everything、光速搜索代码》 关于获取文件全路径 GetFullFileName 函数的优化
  20. 鼠标拖拽缩放面板大小

热门文章

  1. 一个人,仅30天!开发一款3D竞技足球游戏!他究竟经历了些什么?
  2. 根据银行卡号来获取银行名称-java
  3. 全球100位人工智能名人和2500名资深AI人士,将聚首深圳
  4. ​Word文档的隐藏功能​
  5. [转贴]COM Interop 注册相关
  6. 从输入URL到页面加载…
  7. win10中如何找到隐藏的文件
  8. git无法push大文件:this exceeds GitHub‘s file size limit of 100.00 MB
  9. #Cprove7-9 函数应用
  10. P1024 [NOIP2001 提高组] 一元三次方程求解