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

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

C2. Skyscrapers (hard version)

time limit per test

3 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

This is a harder version of the problem. In this version n≤500000n≤500000

The outskirts of the capital are being actively built up in Berland. The company "Kernel Panic" manages the construction of a residential complex of skyscrapers in New Berlskva. All skyscrapers are built along the highway. It is known that the company has already bought nn plots along the highway and is preparing to build nn skyscrapers, one skyscraper per plot.

Architects must consider several requirements when planning a skyscraper. Firstly, since the land on each plot has different properties, each skyscraper has a limit on the largest number of floors it can have. Secondly, according to the design code of the city, it is unacceptable for a skyscraper to simultaneously have higher skyscrapers both to the left and to the right of it.

Formally, let‘s number the plots from 11 to nn. Then if the skyscraper on the ii-th plot has aiai floors, it must hold that aiai is at most mimi (1≤ai≤mi1≤ai≤mi). Also there mustn‘t be integers jj and kk such that j<i<kj<iaiai<ak. Plots jj and kk are not required to be adjacent to ii.

The company wants the total number of floors in the built skyscrapers to be as large as possible. Help it to choose the number of floors for each skyscraper in an optimal way, i.e. in such a way that all requirements are fulfilled, and among all such construction plans choose any plan with the maximum possible total number of floors.

Input

The first line contains a single integer nn (1≤n≤5000001≤n≤500000) — the number of plots.

The second line contains the integers m1,m2,…,mnm1,m2,…,mn (1≤mi≤1091≤mi≤109) — the limit on the number of floors for every possible number of floors for a skyscraper on each plot.

Output

Print nn integers aiai — the number of floors in the plan for each skyscraper, such that all requirements are met, and the total number of floors in all skyscrapers is the maximum possible.

If there are multiple answers possible, print any of them.

Examples

input

Copy

5
1 2 3 2 1

output

Copy

1 2 3 2 1 

input

Copy

3
10 6 8

output

Copy

10 6 6 

Note

In the first example, you can build all skyscrapers with the highest possible height.

In the second test example, you cannot give the maximum height to all skyscrapers as this violates the design code restriction. The answer [10,6,6][10,6,6] is optimal. Note that the answer of [6,6,8][6,6,8] also satisfies all restrictions, but is not optimal.

题意:

给定一个整数n以及一个数组m。

让你构建一个数组a满足:

\(1 \le a_i \le m_i\),且不存在这样的情况\(j < i < k,a_j > a_i < a_k\)

要求满足上述条件的同事,数组的sum和最大。

思路:

我们知道要满足数组的条件,数组必须是一个单峰数组。即我们只需要找到那个数组的峰值的下标即可。

用单调栈维护两个数组:

\(pre[i]\)代表从1到\(i\) 单调不减时最大的前缀和。

\(suf[i]\)代表从\(i\)到\(n\) 单调不升时最大的后缀和。

那么我们找到\(pre[i] + suf[i + 1]\)的最大值下标就是目标数组的峰值下标,然后输出答案即可。

代码:

const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
ll a[maxn];
stack<pll> st;
ll pre[maxn];
ll suf[maxn];

int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    n = readint();
    repd(i, 1, n)
    {
        a[i] = readll();
    }
    ll sum = 0ll;
    repd(i, 1, n)
    {
        pll temp = mp(a[i], 1ll);
        while (!st.empty() && temp.fi <= st.top().fi)
        {
            pll now = st.top();
            st.pop();
            sum -= now.fi * now.se;
            temp.se += now.se;
        }
        st.push(temp);
        sum += temp.fi * temp.se;
        pre[i] = sum;
        // cout << pre[i] << " ";
    }
    // cout << endl;
    while (!st.empty())
    {
        st.pop();
    }
    sum = 0ll;
    for (int i = n; i >= 1; --i)
    {
        pll temp = mp(a[i], 1ll);
        while (!st.empty() && temp.fi <= st.top().fi)
        {
            pll now = st.top();
            st.pop();
            sum -= now.fi * now.se;
            temp.se += now.se;
        }
        st.push(temp);
        sum += temp.fi * temp.se;
        suf[i] = sum;
        // cout << suf[i] << " ";
    }
    // cout << endl;
    ll ans = 0ll;
    int id;
    repd(i, 0, n)
    {
        if (pre[i] + suf[i + 1] > ans)
        {
            ans = pre[i] + suf[i + 1];
            id = i;
        }
    }
    repd(i, id + 2, n)
    {
        a[i] = min(a[i], a[i - 1]);
    }
    for (int i = id - 1; i >= 1; --i)
    {
        a[i] = min(a[i], a[i + 1]);
    }
    repd(i, 1, n)
    {
        printf("%lld%c", a[i], i == n ? '\n' : ' ');
    }

    return 0;
}

原文地址:https://www.cnblogs.com/qieqiemin/p/12358016.html

时间: 2024-07-30 14:02:20

[Codeforces Round #622 (Div. 2)] - C2. Skyscrapers (hard version) (单调栈)的相关文章

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

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 问题 传送门 我是参考了这篇题解传送门,然后按着思路做出了的(但大佬题解中的sumr[]数组操作我没看懂,然后自己改了改). 摘抄: 维护峰值最优 找左右边的第一个比自己小的元素,维护前缀和,找最大的峰值 l[i]:用单调栈维护左边第一个比它小的数 r[i]:用单调栈维护右边第一个比它小的数 suml[i]:左边的前缀和 sumr[i]:右边的前缀和 然后遍历一遍数组,找到

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

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version) 题意: 你是一名建筑工程师,现给出 n 幢建筑的预计建设高度,你想建成峰状,如: 1 2 3 2 1 → 1 2 3 2 1 1 2 3 1 2 → 1 2 3 1 1 8 10 6 → 8 10 6 10 6 8 → 10 6 6 问所有建筑的高度和最大为多少. 思路: 单调递增栈栈顶存储以当前点为峰的单侧最低高度下标,另存储以每个点为峰的左右最大高度和. #includ

Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)

题目链接:http://codeforces.com/contest/1313/problem/C2 题意:有n个房子,每个房子可以建的最高层数为a[i],但不可以出现相邻左右两边房子的层数都比中间高的情况,要求总共层数要尽可能的多,输出每个房子应该建几层. 思路:记录左边比自己小的第一个元素,同时可以求出当i为顶端是的前缀和.然后记录右边第一个比自己小的元素,同时可以求出当i为顶端是的后缀和.然后再遍历一篇,看谁为顶端时,总层数最多,最后再依次确定层数即可. #include<stdio.h>

Codeforces Round #622 (Div. 2)C2 Skyscrapers最大&quot;尖&quot;性矩形,思维

题:https://codeforces.com/contest/1313/problem/C2 题意:给出n个数,分别代表第i个位置所能搭建的最大高度,问以哪一个位置的塔的高度为基准向左的每一个塔都小于等于临近右边的塔,向右每一个塔都大于等于临近的左边的塔所构建的高度之和是最大的,输出最大的高度之和: 分析:我们设一个fir[i]数组,表示当前 i 位置向左能构造的最大高度和(就想阶梯一样,i位置是阶梯的最高处),sec[i]则是向右的: 因为求出这俩个数组后,我们直接o(n)的访问fir[i

Codeforces Round #622 (Div. 2)C2

题意 N长度为500000以内,一个数字两边的数字不能都比他高,最多高一边 求他最大sum.叙述有问题,直接看样例 3 10 6 8 因为6左右都比他高,选择10 6 6或者6 6  8,sum明显前者高 所以答案输出10 6 6 思路: 求出每个a[i]左边(minl[i])和右边(minl[i])最近的一个比他小的数,用前缀和(suml) 和 后缀和(sumr)求得当a[i]是顶点时候sum=suml+sumr-a[i]: 前缀和如果minl[i]==空集(0),那么suml[i]=i*a[

Codeforces Round #344 (Div. 2) 631 C. Report (单调栈)

C. Report time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Each month Blake gets the report containing main economic indicators of the company "Blake Technologies". There are n commodities

Codeforces Round # 555 (Div. 3) C2. Increasing subsequence (complicated version) (贪心)

题目链接:http://codeforces.com/contest/1157/problem/C2 当左右两边数字相同时,需要判断一下取哪边能得到更长的递增序列 #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <cstdio> #include <queue> #include <climits>

Codeforces Round #622 (Div. 2)

A: 题意: 有ABC的三种菜,现在有a个A,b个B,c个C,问能组成多少种不同菜单 思路: abc都大于等于4,肯定是7种,给abc排个序,从大到小举例删减 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define il inline 5 #define it register int 6 #define inf 0x3f3f3f3f 7 #define lowbit(x) (x)&am

Codeforces Round #622 (Div. 2)C(单调栈,DP)

构造出的结果一定是一个单峰/\这种样子的 1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 long long a[500007]; 5 pair<long long,long long>stk[500007]; 6 long long l[500007],r[500007];//记录左/右边最近的比当前小的位置 7 long long ans[500007]; 8 l