bzoj4504 K个串

来源:互联网 发布:香港虚拟主机 知乎 编辑:程序博客网 时间:2024/06/05 14:11

K个串

题目背景:

bzoj4503

分析:

首先考虑如果没有负数,那么我们就可以直接从段的长度从大到小枚举就可以了,然而,这显然不能A题,我们考虑对于每一个位置i,我们维护以它为右端点的每一个子串的和,并且令maxp[i]为当前的这一部分的子串和的最大值,显然,全局的最大值,就是所有maxp[i]的最大值,然后我们用当前最大值所在的i的以其为右端点的子串中的次大值来重新更新,那么将这些操作重复k次即可以得到答案。

然后我们来考虑如何维护c[i],以及在每次更新后,重新找出次大值,首先我们可以发现,如果我们把以i为右端点的所有子串的和求取出来后,我们求取以i + 1为右端点的子串和则只需要,将[last[num[i + 1]] + 1, i + 1]这一段区间的和全部加上num[i + 1]即可,那么我们只需要维护上一个num[i + 1]的出现位置(last数组)即可

然后,对于每一次询问全局的最大值,我们只需要开一个堆即可,然后对于如何找出次大值,并且去除最大值的影响,我们可以选择进行进行的操作是,首先记录maxp,及其对应的i,以及当前的maxp由哪一段区间得到(如一开始都是由[1,i]得到,所以存入1i),还有这一个maxp是以哪一位置为左端点,然后我们每一次取出最大值之后,假设他是maxp[x],且以y为左端点,且由l, r询问得来,那么我们只需要将以当前x为根的,区间[l, y – 1], [y + 1, r]中的询问得到的最大值都放进去即可。

注意:对于每一次由上一个线段树区间加得到下一个,我们可以选择两种方法,标记永久化,或者是标记下方,后者的实现较为麻烦,且容易出现错误,所以这里推荐前者,每一次只需要将标记节点新建即可。

Source


 

 

 

 

0 0