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;
}

posted @ 2021-03-22 14:01  EchoZQN  阅读(24)  评论(0编辑  收藏  举报