先说明,不是所有区间中位数都可以用左偏树维护的,本题是有特殊性的
拿到这道题,相信大部分人都想到了n^2的dp,我一开始也是笨笨地编了那个裸裸的程序,结果怎么都得200ms+
瞬间就有被第一版的0ms暴虐的感觉,忽然发现discuss里惊现某神牛的3字帖:左偏树
这才想到05hhy论文里ms提到了这个题,而且事实上那道题n的范围达到了100000!
哈哈,爽一把
好了,进入正题,简单讲讲这个高级算法
其实本题的解法是贪心,把整个序列分成若干块,每一块都改成那一块的中位数,而且保证每个块的中位数不小于前一个块的
那么就用左偏树维护这几个块的中位数,用栈来维护这些块
S1:(假设前i-1个数的块已经分好了)先把第i个数以一个数新开个块
S2:检查栈顶top的块的中位数是不是比top-1的要小,如果是则转S3,否则继续做下一个数i+1直到n个数都做完
S3:合并top和top-1两个块,转S2
至于中位数怎么维护,其实是很简单的
一个块如果有n个数,你只保留较小的(n+1)div 2个就可以了,用左偏树做个最大堆,最大的元素就是中位数
上述算法在论文里讲的更详细一点,你还可以参考一下那篇论文
本题要求个代价,那就还需要维护一些东西,论文里没有讲,其实也是很简单的
就每个左偏树维护4个东西
堆中元素个数now[i]、这些数的和s[i]、属于这个堆但被从堆中去掉的元素个数go[i]、这些数的和b[i]
最后ans=sigma每个块(该块中位数*now[i]-s[i]+b[i]-go[i]*中位数)
时间复杂度O(nlogn)
代码: