Array Removal(multiset)

Array Removal

Time limit:  1000 ms
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
InputOutputExplanation
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]

题意:给你一个非负整数序列(0<=ai<=1e9),以及一个移除数据的次序(一个全排列)
求操作过程中的最大子段和(删除后位置空缺出来,不合并)

思路:首先由于序列为正整数序列,所以首次操作肯定为所有元素的和。

我们可以有这样的思路,利用一个容器存储所以的字段和,然后每次查询则为容器中的

最大值即为当前最大的子段和,对于每次移除一个元素,可以找到当前元素所属的字段和,

然后将这个字段和从容器中删除,再向容器中加入移除元素后得到的 新子段和。

考虑每一次移除一个元素,可分为两种情况,一种是删除的元素两边都是有元素的,则删除

该元素之后,查询已移除的元素中正好比当前移除位置大跟小的边界,再向容器中添加两个

新字段和,若是当前移除元素刚好为边界即某一个字段的边界时,此时只会只会增加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();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值