Codeforces Round #622 (Div. 2) C2 - Skyscrapers (hard version) 单调栈

从左往右扫,找到比第i个小的第一个数字,l[i] = l[last] + (i - last) * m[i],用单调栈O(n)维护这个过程,再从右往左扫,同理可以算出r数组,注意一下long long

#include <bits/stdc++.h>
using namespace std;
const int N = 5000010;
int m[N], ans[N];
long long l[N], r[N];
stack < int > s;
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &m[i]);
        while (!s.empty() && m[s.top()] > m[i]) {
            s.pop();
        }
        if (s.empty())    l[i] = 1ll * i * m[i];
        else    l[i] = l[s.top()] + 1ll * (i - s.top()) * m[i];
        s.push(i); 
    }
    while (!s.empty())    s.pop();
    for (int i = n; i >= 1; i--) {
        while (!s.empty() && m[s.top()] > m[i]) {
            s.pop();
        }
        if (s.empty())    r[i] = 1ll * (n - i + 1) * m[i];
        else    r[i] = r[s.top()] + 1ll * (s.top() - i) * m[i];
        s.push(i); 
    }
    long long t = 0;
    int peak = 0;
    for (int i = 1; i <= n; i++) {
        long long tot = l[i] + r[i] - m[i];
        if (tot > t)
            peak = i, t = tot;
    }
    ans[peak] = m[peak];
    for (int i = peak - 1; i >= 1; i--)
        ans[i] = min(ans[i + 1], m[i]);
    for (int i = peak + 1; i <= n; i++)
        ans[i] = min(ans[i - 1], m[i]);
    for (int i = 1; i <= n; i++)
        printf("%d ", ans[i]);
    return 0;
}

 

posted @ 2020-02-27 17:10  cminus  阅读(103)  评论(0编辑  收藏  举报