loj 3039
NKOJ

Description

n个蛋糕,每个蛋糕有wi,hi。选m个蛋糕满足j=1mwkjj=1m|hkjhkj+1 |
因为蛋糕摆成一个环所以k1=km+1

Solution

我因为最近天天做dp,直接就往dp上想的,其实是思维僵化。
然后本来可以骗46分的,因为没有考虑到答案可能是负数+数据点捆绑直接宝菱。
dp就前缀和优化dp就可以做了,很好写。
当然前面肯定要想到j=1m|hkjhkj+1 |这个的最小值,显然是按h从小到大排后得到的,因此其实是2(maxhminh)
这样按h排序,消除影响。
枚举最后一个选的点i,发现第一个选的点j是具有决策单调性的(只会打表)
整体二分+可删对顶堆

这东西挺恶心的,总之我调了好久,经常推翻重来

总结一下:

整体二分:维护两个指针tl,tr,复杂度是nlog22n的因为log2n层,每次[L,R]结束时,tl=L,tr=R。左递归开始时肯定是取[L,R]中一个点pos,tl=pos,tr=pos,左边递归结束时一定是也tl=pos,tr=pos(左dfs树最靠右的叶子),此时再右递归转移到 tl=R,tr=R。考虑这一层的转移,显然是RL+1次,每次O(log2n),而又有有log2n层。
当然上面的复杂度证明中,不一定是确切的等于(如 tl 会有和 midm+1min,每层跟mid有关总体也是nlog2n级别的),易证影响不大/kk。

对顶堆:因为你需要维护前m大的和(sumw),如果你只存一个大根堆,删除或者加入是维护不了的。
因此前m大的数存入小根堆Q1里,其它小的数存入大根堆Q2,每次加入一个数判断如果大于Q1,Q2分界,把Q1.top()加入Q2,把该数加入Q1。否则直接加入Q2
然后删除也维护两个可删堆D1,D2。每次删除的时候判断删的数是在Q1中则加入Q2,反之……
每次取出堆顶前判断是如果已经在可删堆内,直接删了(这是可删堆的常规操作……)

!!! 这里我犯过一个错误

你维护的sumw不是你Q1里面实际所有值的和。而是里面没有在D1中(没被删)的和。
Q1D1才是真正的前m大。Q1里面还存在着一些已经死去的傀儡……
所以实际上Q1.size()不一定等于m,我们需要单独维护一个sz1(这个很简单)

实现细节:不知道我的实现方式会不会比别人复杂

强制Q1,Q2的堆顶是存在的(没被删),需要每次pop()后,删点即可。
Add的就是上面对顶堆说的那堆。
Del比较复杂,如果删除的是在Q1中的,用Q2.top()替代删除的那个,即把Q2.top()加入Q1,删除的值加入D1。这样也保证了sz1守恒。

以后写博客尽量宏观一点,不要太啰嗦,不过我感觉题目都好细节呀。