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

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1295 [TJOI2011]书架(线段树dp)相关的知识,希望对你有一定的参考价值。

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 fi1

和最小 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)的主要内容,如果未能解决你的问题,请参考以下文章

[TJOI2011]书架

P3842 [TJOI2007]线段 思维 ,DP

BZOJ5334 [TJOI2018] 数学计算 线段树分治

TJOI2007 线段

[HEOI2016&TJOI2016] 排序(线段树)

bzoj4552/Tjoi2016&Heoi2016排序——二分+线段树/平衡树+线段树分裂与合并