Array Removal
Memory limit: 128 MB
Alex has an array of N integers. On this array he can perform the following operation: choose an element that was not previously chosen and mark it as unavailable. Alex wants to perform exactly N operations, until all the elements are marked.
Alex defines the cost of a subarray as the sum of all the elements in the subarray. Before performing an operation, Alex wants to know the maximum cost of a subarray that doesn't contain any unavailable elements.
Standard input
The first line contains a single integer N, the length of the array.
The second line contains the N values of the array.
The third line contains a permutation of size N, representing the indices of the elements chosen for the operations, in order.
Standard output
The output should contain N lines. On each line output a single integer, the answer before each operation.
Constraints and notes
- 1 ≤ N ≤ 10^5
- The values of the array are integers between 0 and 10^9
Input | Output | Explanation |
---|---|---|
5 6 1 2 3 2 2 5 1 4 3 | 14 7 6 5 2 | Available elements - Max sum - Max sum subarray: 11111 - 14 - [1, 5]11111−14−[1,5] 10111 - 7- [3, 5]10111−7−[3,5] 10110 - 6 - [1, 1]10110−6−[1,1] 00110 - 5 - [2, 3]00110−5−[2,3] 00100 - 2 - [3, 3]00100−2−[3,3] |
6 8 3 4 1 5 10 1 4 6 3 2 5 | 31 23 15 7 5 5 |
111111 - 31 - [1, 6]111111−31−[1,6] 011111 - 23 - [2, 6]011111−23−[2,6] 011011 - 15 - [5, 6]011011−15−[5,6] 011010 - 7 - [2, 3]011010−7−[2,3] 010010 - 5 - [5, 5]010010−5−[5,5] 000010 - 5 - [5, 5]000010−5−[5,5] |
思路:首先由于序列为正整数序列,所以首次操作肯定为所有元素的和。
我们可以有这样的思路,利用一个容器存储所以的字段和,然后每次查询则为容器中的
最大值即为当前最大的子段和,对于每次移除一个元素,可以找到当前元素所属的字段和,
然后将这个字段和从容器中删除,再向容器中加入移除元素后得到的 新子段和。
考虑每一次移除一个元素,可分为两种情况,一种是删除的元素两边都是有元素的,则删除
该元素之后,查询已移除的元素中正好比当前移除位置大跟小的边界,再向容器中添加两个
新字段和,若是当前移除元素刚好为边界即某一个字段的边界时,此时只会只会增加1个(单边界)或者
0个新字段(双边界)。
说了这么多,到底有什么容器可以实现这样的功能呢:又能准确删除元素,插入元素,又能快捷查询最大值。
这其实就是multiset啦,利用一个可重复集合就可以实现以上的操作了。
最后再说一下注意点:
对于multiset,虽然集合中允许重复元素的旬在,但当你删除一个元素时利用
s.erase(x) 删除元素时,multiset是会将集合中所有的x都删除的。
若只想删除一个x,则需要利用迭代器来指定删除,这里提供一种写法;
s.erase(s.lower_bound(x)) 利用lower_bound 返回一个x的迭代器地址,再将其删除就好了。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cstring>
using namespace std;
#define ll long long
const int maxn = 100000;
ll a[maxn + 50],b[maxn + 50],sum[maxn + 50];
void work()
{
int n; scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i] = sum[i-1] + a[i];
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
multiset<ll> s;
set<ll> ss;
ss.insert(0);
ss.insert(n+1);
s.insert(sum[n]);
for(int i=1;i<=n;i++)
{
printf("%lld\n",*(--s.end()));
int R = *(ss.lower_bound(b[i]));
int L = *(--ss.lower_bound(b[i]));
s.erase(s.lower_bound(sum[R-1]-sum[L])); //删除一个元素
if(b[i]-1!=L) s.insert(sum[b[i]-1]-sum[L]); //判断边界(虽说好像不判也没什么关系,只是集合中会多了一些0)
if(R-1!=b[i]) s.insert(sum[R-1]-sum[b[i]]);
ss.insert(b[i]);
}
}
int main()
{
work();
}