[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<i <k aj="" and=""> ai <akaj> ai<ak. Plots jj and kk are not required to be adjacent to ii. </akaj> </k>
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;
}