题目链接:
Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)
题目解析:
在C1中,我们让每一个点作为顶点,然后遍历数组,这在C2中显然会超时,现在考虑如何优化.
在遍历的过程中,如果一个点可建造的高度h[i]大于等于当前可建造的最大高度maxhigh,显然不用更新maxhigh.只有当h[i]<maxhigh,才会把maxhigh更新为a[i].也就是说,我们无需遍历每一个点,只需要快速找到一个点左右两边第一个小于它的数.这显然是单调栈问题
(真没想到之前刚刷了几道单调栈的题就派上用场了^_^)
AC代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXX = 500005;
ll h[MAXX],n;
ll ls[MAXX],rs[MAXX],sum[MAXX];
ll l[MAXX],r[MAXX];
ll ans[MAXX];
stack<int> s;
int main()
{
cin >> n;
for (int i=1; i<=n; i++)
{
cin >> h[i];
sum[i] = sum[i-1] + h[i];
}
for (int i=1;i<=n; i++)
{
while(!s.empty() && h[s.top()] >= h[i]) s.pop();
if (s.empty()) l[i] = 0;
else l[i] = s.top();
s.push(i);
}
while(!s.empty()) s.pop();
for (int i=n; i; i--)
{
while(!s.empty() && h[s.top()] >= h[i]) s.pop();
if (s.empty()) r[i] = n+1;
else r[i] = s.top();
s.push(i);
}
for (int i=1; i<=n; i++)
ls[i] = ls[l[i]] + (i-l[i])*h[i];
for (int i=n; ~i; i--)
rs[i] = rs[r[i]] + (r[i]-i)*h[i];
ll maxi = 0, maxv = -1;
for (int i=1; i<=n; i++)
if (ls[i]+rs[i]-h[i] > maxv)
maxi = i, maxv = ls[i]+rs[i]-h[i];
for (int i=maxi; i; i=l[i])
for (int j=i; j>l[i]; j--) ans[j] = h[i];
for (int i=maxi; i; i=r[i])
for (int j=i; j<r[i]; ++j)
ans[j] = h[i];
for (int i=1; i<=n; i++)
cout << ans[i] << ' ';
}