題目鏈接:
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] << ' ';
}