Codeforces Round #622 (Div. 2)C2. Skyscrapers (hard version) time limit per test3 seconds memory lim

C2. Skyscrapers (hard version)
time limit per test3 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
This is a harder version of the problem. In this version n≤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 n plots along the highway and is preparing to build n 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 1 to n. Then if the skyscraper on the i-th plot has ai floors, it must hold that ai is at most mi (1≤ai≤mi). Also there mustn’t be integers j and k such that j<iai<ak. Plots j and k are not required to be adjacent to i.

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 n (1≤n≤500000) — the number of plots.

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

Output
Print n integers ai — 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
inputCopy
5
1 2 3 2 1
outputCopy
1 2 3 2 1
inputCopy
3
10 6 8
outputCopy
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] is optimal. Note that the answer of [6,6,8] also satisfies all restrictions, but is not optimal.

题意:给了n个楼层高度,让你去构造 使得每个楼层的左右两侧不得大于该楼层,要求所有楼层总和尽可能大。

思路:其实 本质就是找到一个最高的点,然后左边单调不增,右边单调不增即可
这不就是维护两个单调栈吗
从左往右边扫过去,用l[i]来记录 a[i]最左边>他的数
这样的话我们用一个lsum[i] 来维护从左往右的一个前缀和
lsum[i]=lsum[j]+(i-j) * a[i] 其中i表示当前位置 j表示i的最左边比a[i]大的数的前一个位置
这样来维护一个以i为最高点的左边的前缀和
接下来从右往左扫,同理
那么对于lsum[i]+rsum[i] 就是a[1]+a[2]+a[3]+a[4]+…+a[i]+a[i]+a[i+1]+…+a[n]
我们只要一个for枚举lsum和rsum的和减去ai 取最大值 记录下标i 对原序列 左右更新输出即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define me(a,x) memset(a,x,sizeof a)
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define all(x) (x).begin(), (x).end()
#define pb(a) push_back(a)
#define paii pair<int,int>
#define pali pair<ll,int>
#define pail pair<int,ll>
#define pall pair<ll,ll>
#define fi first
#define se second
int l[500005],r[500005];
ll a[500005];
ll lsum[500005],rsum[500005];
int main()
{
    int n;
    cin>>n;
    repd(i,1,n) cin>>a[i];
    for(int i=1,j; i<=n; i++){

        j=i-1;
        while(j>=1 && a[j]>a[i])
            j=l[j];
        l[i]=j;
        lsum[i]=lsum[j]+(i-j)*a[i];
        // cout<<i<<" "<<l[i]<<" "<<lsum[i]<<endl;
    }
    int id;
    ll ma=0;
    for(int i=n,j; i; i--){
        j=i+1;
        while(j<=n && a[j]>a[i])
            j=r[j];
        r[i]=j;
        rsum[i]=rsum[j]+(j-i)*a[i];
        // cout<<i<<" "<<r[i]<<" "<<rsum[i]<<endl;
        if(lsum[i]+rsum[i]-a[i]>ma)
        {
            ma=lsum[i]+rsum[i]-a[i];
            id=i;
        }
    }
    // cout<<id<<endl;
    vector<int> v;
    for(int i=id-1; i; i--)
    {
        if(a[i]>a[i+1])
            a[i]=a[i+1];
        v.pb(a[i]);
    }
    for(int i=v.size()-1; i>=0; i--)
        cout<<v[i]<<" ";
    cout<<a[id]<<" ";
    for(int i=id+1; i<=n; i++)
    {
        if(a[i]>a[i-1])
            a[i]=a[i-1];
        cout<<a[i]<<" ";
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会c语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值