E. Skyline Photo 线段树 + 单调栈 + dp
E. Skyline Photo
题目大意:
有 \(n\) 栋楼房,每栋楼有一个高度 \(h_i\) 和美丽值 \(b_i\)。
现在,你需要把这 \(n\) 栋楼房划分成若干个连续段,每一个连续段的美丽值为该段中最矮的楼房的美丽值。总的划分美丽值为每个连续段的美丽值之和。
你需要求出最大可能的总划分美丽值。
题解:
AC_CODE
#include <bits/stdc++.h>
#define lson (id<<1)
#define rson (id<<1|1)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 3e5+10;
typedef long long ll;
ll maxs[maxn<<2],dp[maxn],lazy[maxn<<2];
int h[maxn],b[maxn];
int sta[maxn];
void change(int id,ll val){
maxs[id] += val;
lazy[id] += val;
}
void push_down(int id){
if(!lazy[id]) return ;
change(lson,lazy[id]);
change(rson,lazy[id]);
lazy[id] = 0;
}
void push_up(int id){
maxs[id] = max(maxs[lson],maxs[rson]);
}
void update(int id,int l,int r,int x,int y,ll val){
// printf("update: id = %d l = %d r = %d x = %d y = %d val = %lld\n",id,l,r,x,y,val);
if(x<=l&&y>=r){
change(id,val);
return ;
}
push_down(id);
int mid = (l+r)>>1;
if(x<=mid) update(lson,l,mid,x,y,val);
if(y>mid) update(rson,mid+1,r,x,y,val);
push_up(id);
}
ll query(int id,int l,int r,int x,int y){
if(x<=l&&y>=r) {
return maxs[id];
}
ll ans = -inf;
push_down(id);
int mid = (l+r)>>1;
if(x<=mid) ans = max(ans,query(lson,l,mid,x,y));
if(y>mid) ans = max(ans,query(rson,mid+1,r,x,y));
return ans;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
int now = 0;
for(int i=1;i<=n;i++){
while(now&&h[i]<h[sta[now]]){
update(1,0,n,sta[now-1],sta[now]-1,-b[sta[now]]);
now--;
}
update(1,0,n,sta[now],i-1,b[i]);
sta[++now] = i;
dp[i] = query(1,0,n,0,i-1);
// printf("dp[%d]=%lld\n",i,dp[i]);
update(1,0,n,i,i,dp[i]);
}
printf("%lld\n",dp[n]);
return 0;
}