Skyscrapers (hard version)
预处理出每个点作为顶点时左右两边的贡献。然后找出那个最大值,再根据那个点往左右修改就好了。。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
const int maxn = 5e5 + 10;
LL a[maxn];
LL stack[maxn], suml[maxn], sumr[maxn];
int main()
{
LL n;
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
}
LL head = 0;
for (LL i = 1; i <= n; i++)
{
while (head && a[stack[head]] > a[i])head--;
suml[i] = suml[stack[head]] + (i - stack[head]) * a[i];
stack[++head] = i;
}
head = 0;
stack[0] = n + 1;
for (LL i = n; i >= 1; i--)
{
while (head && a[stack[head]] > a[i])head--;
sumr[i] = sumr[stack[head]] + (stack[head] - i) * a[i];
stack[++head] = i;
}
LL sum = 0, ans = -1, flag;
for (int i = 1; i <= n; i++)
{
sum = suml[i] + sumr[i] - a[i];
if (sum > ans)
{
ans = sum;
flag = i;
}
}
for (int i = flag - 1; i >= 1; i--)
{
if (a[i] > a[i + 1])a[i] = a[i + 1];
}
for (int i = flag + 1; i <= n; i++)
{
if (a[i] > a[i - 1])a[i] = a[i - 1];
}
for (int i = 1; i <= n; i++)
{
printf("%lld ", a[i]);
}
return 0;
}