题意
给定n个建筑,每个建筑的高度为hi(hi唯一),每个建筑有一个美丽值为bi,给这些建筑拍照,拍照的要求是每次拍照的建筑必须是连续的,每个建筑只能且精确的出现在一张照片,每个照片的美丽值为这个照片里面的最低建筑物的美丽值。
求所有照片的美丽值之和最大。
n<=3e5 -1e9 <= bi <= 1e9
思路
以第i张建筑为结尾拍照,可以分为考虑第i张照片的美丽值和不考虑两种情况,考虑的话又有两种情况,1.自己一张照片 2.和前面连续的都比它高的在一张照片,不考虑是从前面比它小的在一张照片
定义f[i]表示以第i个建筑结尾拍照的最大美丽值
用转移方程表示为
1.f[i] = f[i - 1] + b[i]
2.f[i] = max(f[k] ) + b[i] 表示第i个建筑之前到第一个比它低的建筑物之间的最大美丽值加上第i个建筑的美丽值(只需要保证h[k] 最小)应该包含k,但是我第一次没有包含k竟然也过了,因为第k个代表所有大的都在这里面。
3.f[i] = f[k] k表示i之前第一个比它低的建筑下标(可以通过传递性,因为在第k张照片的时候考虑了比它小的)
在只用找第一个比他小的,可以使用单调栈
但是这并不能表示第二情况求max(f[k]),根据单调栈的性质我们可以把比它大的都会删除,只用考虑max(f[k])我们可以把这个信息保留在这个点上,用一个栈来维护。
代码
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<unordered_set>
#include<unordered_map>
using namespace std;
#define x first
#define y second
#define int long long
typedef pair<int ,int > PII;
typedef long long ll;
const int N = 3e5 + 10;
int h[N];
int b[N];
int f[N];
int q[N];
int maxp[N];
signed main(){
int n;
scanf("%lld",&n);
for(int i = 1;i <= n;i++){
scanf("%lld",&h[i]);
}
for(int i = 1;i <= n;i++){
scanf("%lld",&b[i]);
}
int tt = 0;
h[0] = 2e9;
maxp[0] = 0;
for(int i = 1;i <= n;i++){
f[i] = f[i - 1] + b[i];
int mp = -2e9;
while(0 <= tt && h[q[tt]] >= h[i]) mp = max(mp,maxp[tt --]);
f[i] = max(mp + b[i],f[i]);
if(q[tt] != 0 ) f[i] = max(max(f[q[tt]],f[q[tt]] + b[i]),f[i]);
q[++tt] = i;
maxp[tt] = max(mp,f[i]);
}
cout << f[n] ;
return 0;
}