Codeforces Round #622 C2.Skyscrapers (hard version)
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<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 (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
5
1 2 3 2 1
1 2 3 2 1
3
10 6 8
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; }