[线段树][二分][DP]luogu P1295 [TJOI2011]书架
题面
https://www.luogu.com.cn/problem/P1295
分析
很容易想到设 $f_i$ 表示选到第 $i$ 个的最小最大值之和,则有
$f_i=min(f_j+max(hj~hi) (j<i)$
发现这里有一段连续的东西,然后考虑线段树。
考虑插入一个 $h_i$ 的影响,就会使从 $i$ 向前找到的第一个 $j(h[j-1]>=h[i])$ 的 $[i,j]$ 区间 $h$ 值全部设为 $h_i$
那么开三棵线段树,一个维护 $f$ ,一个维护 $h$ ,一个维护 $max(h_j~h_i)$
查找 $h$ 最值时二分即可
代码
#include <iostream> #include <cstdio> #define lson (x<<1) #define rson ((x<<1)+1) using namespace std; typedef long long L; const L Inf=1ll<<62; const int N=1e5+10; int n,m,h[N],rev[N]; L t[4*N],lz[4*N],f[4*N],g[4*N]; void Pushdown(int x) {if (!lz[x]) return;g[lson]=f[lson]+lz[x];g[rson]=f[rson]+lz[x];lz[lson]=lz[rson]=t[lson]=t[rson]=lz[x];lz[x]=0;} void Change(int x,int l,int r,int ll,int rr,int val) { if (r<l) return; if (ll<=l&&r<=rr) {g[x]=f[x]+val;t[x]=lz[x]=val;return;} int mid=l+r>>1; Pushdown(x); if (ll<=mid) Change(lson,l,mid,ll,rr,val); if (mid<rr) Change(rson,mid+1,r,ll,rr,val); t[x]=max(t[lson],t[rson]);f[x]=min(f[lson],f[rson]);g[x]=min(g[lson],g[rson]); } void Insert(int x,int l,int r,int k,int val) { if (l==r) {g[x]=val+t[x];f[x]=val;return;} int mid=l+r>>1; Pushdown(x); if (k<=mid) Insert(lson,l,mid,k,val); else Insert(rson,mid+1,r,k,val); f[x]=min(f[lson],f[rson]);g[x]=min(g[lson],g[rson]); } int Get(int x,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) return t[x]; int mid=l+r>>1,ans=0; Pushdown(x); if (ll<=mid) ans=Get(lson,l,mid,ll,rr); if (mid<rr) ans=max(ans,Get(rson,mid+1,r,ll,rr)); return ans; } int Query(int l,int r,int k) { int mid,ans=r+1,ub=r; while (l<=r) { mid=l+r>>1; if (Get(1,1,n,mid,ub)<k) ans=mid,r=mid-1; else l=mid+1; } return ans; } L Query(int x,int l,int r,int ll,int rr) { if (ll<=l&&r<=rr) return g[x]; int mid=l+r>>1; L ans=Inf; Pushdown(x); if (ll<=mid) ans=Query(lson,l,mid,ll,rr); if (mid<rr) ans=min(ans,Query(rson,mid+1,r,ll,rr)); return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&h[i]); Change(1,1,n,1,1,h[1]); for (int i=1,s=0,j=1;i<=n;i++) { s+=h[i];while (s>m) s-=h[j++]; Change(1,1,n,Query(j,i-1,h[i]),i,h[i]); if (i==n) return printf("%lld",Query(1,1,n,j,i)),0; Change(1,1,n,i+1,i+1,h[i+1]);Insert(1,1,n,i+1,Query(1,1,n,j,i)); } }
在日渐沉没的世界里,我发现了你。