For any segment with at least three elements, if there exists such that and or , then the segment can be split into two segments and . It may be proven that the sum of the values of the two segments is at least as high as the value of the initial segment. More generally, if a segment isn't strictly increasing or strictly decreasing, we can split it into two segments without lowering the total value. Therefore, an optimal solution can be constructed with only strictly increasing or decreasing segments. This paves the way for several key properties.
Define array of length such that . If the current segment is increasing, then for and . If the current segment is decreasing, then for and . Between any two adjacent selected segments and , must not included in our answer. With this formulation, adding integer to all elements is equivalent to performing the point updates and .
Now, the problem becomes selecting segments on rather than the original , where each segment contributes the absolute value of the sum of its elements to the final answer. Every two neighboring segments must be separated by at least one element (see above), and all elements in each segment must be either or . One way to go from here is with a segment tree. Each Node stores the maximum value of its segment for each of the four cases of taking or not taking the first or last element, as well as the border elements of its segment. When merging, we must pay attention to only combine two segments together if the signs of their border elements to be combined are the same to ensure that the combined segment continues to be either strictly increasing or decreasing.
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;typedef long long ll;Code Snippet: Segtree Node (Click to expand)Code Snippet: Segtree (Click to expand)int main() {ios_base::sync_with_stdio(false);
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!