给你n,再给你n个数,最后给一个k
求出这个序列的第k大连续区间和; (注意这里重复出现的数字只被统计一次)
N(1<=N<=50000)
ai(1<=ai<=100)
K(1<=K<=(n+1)*n/2).
思路:
预处理前缀和。并将其离散化(去重)。
二分答案,然后每次判断中,遍历前缀和Bi,然后查找有多少个jX,也就是有多少个子序列的和是大于X的,即使求有多少个Bj小于【Bi-X】,这部分查询我们可以用树状数组实现,方法类似于树状数组求逆序对。
查询方法简要说一下,也就是当遍历到Bi的时候,我们找到【Bi-ans】在离散化后在树状数组对应的下标Y,然后查询get(1,Y)看之前出现过的Bi有多少个在这个范围,然后ret+=这部分,最后把Bi插入到树状数组中
复杂度分析: 外层二分是logMAXX咯,然后每次nlogn
所以总的复杂度是nlognlogMAXX,MAXX等于区间和的上界
【主席树的做法见最后面】
二分参考代码:
#include
#include
#include
#include
#include
#include
#include
主席树加堆的代码(复杂度klogn,适用于k较小的情况)
同样是求出前缀和sum【】,去重离散化,用idx【】建主席树
step1:把每个si对应找到最小的sj 丢进最大堆。
step2:每次取出堆顶Si,便是当前最大的区间和。
step3:然后找到堆顶元素的Si对应的次小的sj丢进堆里
重复step2,3 k次,得到第k大
证明:显然每次取出来的都是最大的区间和,而对取出来的是【si,sj】(sj是对应于si的第p小的数),那么下次只要找一个 si对应的 第 p+1小的数即可。。。这部分就用到主席树,每次在区间【1,idx【si】-1】找到 第p+1小的sj
#include
#include
#include
#include
#include
#include
#include