这是一道我题解都差点没看懂的题目,DP和线段树融合的出神入化
注释应该写的挺清楚
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define lch(x) x<<1
#define rch(x) x<<1|1
#include<cmath>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
struct node{
int l,r;
ll g,sum;// g为原先的dp值,sum为此次所求值
ll hm,hs;// hm为高度最大值 hs为高度最小值
}tr[maxn*4];
ll h[maxn],L[maxn],lazy[maxn*4];
void pushup(int k){
tr[k].hm=max(tr[lch(k)].hm,tr[rch(k)].hm);
tr[k].hs=min(tr[lch(k)].hs,tr[rch(k)].hs);
tr[k].g=min(tr[lch(k)].g,tr[rch(k)].g);
tr[k].sum=min(tr[lch(k)].sum,tr[rch(k)].sum);
}
void pushdown(int k){
if(lazy[k]){
lazy[lch(k)]=lazy[rch(k)]=lazy[k];
tr[lch(k)].hm=tr[lch(k)].hs=tr[rch(k)].hm=tr[rch(k)].hs=lazy[k];
tr[lch(k)].sum=tr[lch(k)].g+lazy[k];
tr[rch(k)].sum=tr[rch(k)].g+lazy[k];
lazy[k]=0;
}
}
void build(int k,int l,int r){
tr[k].l=l,tr[k].r=r;
if(l==r)return ;
int mid=l+r>>1;
build(lch(k),l,mid),build(rch(k),mid+1,r);
}
void ChangeHeight(int k,int x,int y,int num){
if(num<=tr[k].hs)return;// 比最小的还小,不会对答案产生影响,返回
int l=tr[k].l,r=tr[k].r;
if(l>=x&&r<=y){
if(tr[k].hm<=num){ // 如果大于最大值,那么该区间内所有的sum值都需要更新一次
lazy[k]=tr[k].hm=tr[k].hs=num;
tr[k].sum=tr[k].g+num;
return ;
}
}
pushdown(k);
int mid=l+r>>1;
if(x<=mid)ChangeHeight(lch(k),x,y,num);
if(y>mid)ChangeHeight(rch(k),x,y,num);
pushup(k);
}
ll Query(int k,int x,int y){
int l=tr[k].l,r=tr[k].r;
if(l>=x&&r<=y)return tr[k].sum;// 正常的查询
pushdown(k);
int mid=l+r>>1;
ll res=1e18;
if(x<=mid)res=min(res,Query(lch(k),x,y));
if(y>mid)res=min(res,Query(rch(k),x,y));
pushup(k);
return res;
}
void ChangeDp(int k,int x,int num){
int l=tr[k].l,r=tr[k].r;
if(l==x&&r==x){
tr[k].g=num;return;// 单点修改DP基底值
}
pushdown(k);
int mid=l+r>>1;
if(x<=mid)ChangeDp(lch(k),x,num);
else ChangeDp(rch(k),x,num);
tr[k].g=min(tr[lch(k)].g,tr[rch(k)].g);
}
int n,l;
int main(){
scanf("%d%d",&n,&l);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&h[i],&L[i]);
}
build(1,0,n);
ll Sum=0,temp=1,ans=0;
for(int i=1;i<=n;i++){
Sum+=L[i];
while(Sum>l)temp++,Sum-=L[temp-1];
ChangeHeight(1,temp-1,i-1,h[i]);// 该新书的可放置范围为temp-1->i-1
ans=Query(1,temp-1,i-1); // 查询最优值
if(i!=n)ChangeDp(1,i,ans); // 改变前面的DP基值,做到累计答案
}
cout<<ans;
}