• Codeforces Round #622 C2.Skyscrapers (hard version)


    This is a harder version of the problem. In this version n500000n≤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 (1aimi1≤ai≤mi ). Also there mustn't be integers jj and kk such that j<i<kj<i<k and aj>ai<akaj>ai<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 (1n5000001≤n≤500000 ) — the number of plots.

    The second line contains the integers m1,m2,,mnm1,m2,…,mn (1mi1091≤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
    5
    1 2 3 2 1
    Output
    1 2 3 2 1 
    Input
    3
    10 6 8
    Output
    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.

    看到5e6的数据规模肯定不能O(n^2)暴力了,可以考虑单调栈。首先求出每个位置的最大左侧非递减序列和并存储到up[i](包括自己),可以用一个单调栈来维护。同理求出每个位置的最大右侧非递增序列和存到down[i],复杂度都为O(n).然后枚举每个位置,统计up[i]+down[i]-a[i](重复加了a[i],要减去一个),找到最大的一个位置往两边构造即可。注意这里单调栈的写法,我一开始直接用数组元素往里push,维护单调性时复杂度就可能很高,在第九个点T了...最后学习https://blog.csdn.net/weixin_44164153/article/details/104486676?fps=1&locationNum=2博客里的写法,改用数组下标往栈里push就能过了。

    #include <bits/stdc++.h>
    using namespace std;
    long long a[500005],up[500005]={0},down[500005]={0},out[500005]={0};//up[i]表示包括i最大非递减序列的和  比较up[i]+down[i]-a[i]即可(减去一个重复的) 
    int n;
    int main()
    {
        cin>>n;
        int i,j,k;
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        stack<int>s; 
        s.push(0);
        for(i=1;i<=n;i++)
        {
    //        if(a[i]>s.top())
    //        {
    //            up[i]=up[i-1]+a[i];
    //            //s.push(a[i]);
    //            s.push(i);
    //        }
    //        else
    //        {
    //            long long cnt=0,tot=0;
    //            while(s.size()&&s.top()>a[i])
    //            {
    //                tot+=s.top();
    //                cnt++;
    //                s.pop();
    //            }
    //            for(j=1;j<=cnt+1;j++)//出去的个数加上新进来的一个 
    //            {
    //                s.push(a[i]);1 
    //            }
    //            up[i]=a[i]*(cnt+1)+up[i-1]-tot;
                while(s.size()&&a[s.top()]>=a[i])
                {
                    s.pop();
                }
                up[i]=up[s.top()]+(i-s.top())*a[i];//有跨越的直接乘a[i]加过去即可 
                s.push(i);
    //        }
        }
        while(s.size())s.pop();
        s.push(n+1);//占位 
        for(i=n;i>=1;i--)
        {
    //        if(a[i]>s.top())
    //        {
    //            down[i]=down[i+1]+a[i];
    //            //s.push(a[i]);
    //            s.push(i);
    //        }
    //        else
    //        {
    //            long long cnt=0,tot=0;
    //            while(s.size()&&s.top()>a[i])
    //            {
    //                tot+=s.top();
    //                cnt++;
    //                s.pop();
    //            }
    //            for(j=1;j<=cnt+1;j++)//出去的个数加上新进来的一个 
    //            {
    //                s.push(a[i]);
    //            }
    //            down[i]=a[i]*(cnt+1)+down[i+1]-tot;
                while(s.size()&&a[s.top()]>=a[i])
                {
                    s.pop();
                }
                down[i]=down[s.top()]+(s.top()-i)*a[i];
                s.push(i);
    //        }
        }
        long long ans=0,num=0;
        for(i=1;i<=n;i++)
        {
            if(up[i]+down[i]-a[i]>ans)
            {
                ans=up[i]+down[i]-a[i];
                num=i;
            }
        }
        //构造输出序列
        out[num]=a[num]; 
        for(j=num-1;j>=1;j--)
        {
            out[j]=min(a[j],out[j+1]);
        }
        for(j=num+1;j<=n;j++)
        {
            out[j]=min(a[j],out[j-1]);
        }
        for(i=1;i<=n;i++)
        {
            cout<<out[i]<<' ';
        }
        return 0;
    }
  • 相关阅读:
    线性DP SGU167 I-country
    背包问题 POJ1742 Coins
    背包问题 codevs2210 数字组合
    dfs+贪心 BZOJ4027 [HEOI2015] 兔子与樱花
    spfa最短路+DP BZOJ1003 [ZJOI2006] 物流运输
    矩阵乘法 POJ3070 Fibonacci
    tarjan+spfa最短路 BZOJ1179 [Apio2009] Atm
    欧拉函数 BZOJ2190 [SDOI2008] 仪仗队
    矩阵乘法 洛谷 P3390【模板】矩阵快速幂
    裴蜀定理 BZOJ2299[HAOI2011] 向量
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12362308.html
Copyright © 2020-2023  润新知