题意: 给了一堆楼 要求 不能存在 i < j < k 时, 出现 ai > aj < ak 的情况 不一定非要挨着 楼高有限制 不得超过 mi
官方题解是
单调栈 正着一遍 反着一遍就可以了
正着:dp[i]前i个保持递增序列的最大前缀和
反着就递减的最大后缀和
然后on扫最大
我的ST表 + (贪心)分治
找到最小值 要么左边全是最小值 要不就是右边
选择 一个 (r−mins.second)∗mins.first+s1+mins.first 或 (mins.second−l)∗mins.first+s2+mins.first 一个比较大的固定 贪心的选取它 接着分治另一边
由于最小的已经固定 所以另一边不考虑固定边可能会影响
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 5;
int lg[maxn];
int a[maxn], b[maxn];
pair<int, int> f[maxn][30];
int n, m;
void ST_build() {
for(int i = 1; i <= n; i ++ ) f[i][0] = make_pair(a[i], i);
int t = (lg[n]-1)/(lg[2]-1) + 1;
for(int j = 1; j < t; j ++ ) {
for(int i = 1; i <= n - (1 << j) + 1; i ++ ) {
f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
}
pair<int, int> ST_query(int l, int r){
int k = (lg[r - l + 1] - 1);
return min(f[l][k], f[r - (1 << k) + 1][k]);
}
int solve(int l, int r) {
if(l > r) return 0;
if(l == r) return b[l] = a[l];
pair<int, int> mins = ST_query(l, r);
int s1 = solve(l, mins.second - 1);
int s2 = solve(mins.second + 1, r);
if((r - mins.second) * mins.first + s1 > (mins.second - l) * mins.first + s2) {
for(int i = mins.second; i <= r; i ++) b[i] = mins.first;
return (r - mins.second) * mins.first + s1 + mins.first;
} else {
for(int i = l; i <= mins.second; i ++) b[i] = mins.first;
return (mins.second - l) * mins.first + s2 + mins.first;
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0);
memset(f, 0x3f, sizeof(f));
for(int i = 1; i < maxn; i ++){
lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
}
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
ST_build();
solve(1, n);
for(int i = 1; i <= n; i ++) cout << b[i] << " ";
return 0;
}