[Baltic2004]sequence。。。初学左偏树

来源:互联网 发布:淘宝产品评测报告 编辑:程序博客网 时间:2024/06/06 01:27

 这题我想非常非常久都不知道怎么做,学习了05黄源河的论文才明白如何做的,思路非常不错

 

同时学习了性价比很高的可合并堆---左偏树


觉得这题不好想到,这里我用自己的话复述一下论文中的内容

 


先假设是b1 ≤ b2 ≤ … ≤ bn并非严格递增。(如果需要严格递增我们可以给数 a[i] 变成 a[i]-i。。

这样b只要非下降就可以了(这个技巧非常不错))
初步思路。
当a1<a2<...<an 那么bi=ai是最优值
当a1>a2>...>an 那么他们的中位数显然为最优值
把n个数分成m个区间。。每个区间的b值相同。每个区间的b值为该区间的中位数,
接下来就是要如何证明了。

取出任意一段序列 a1,a2....am  分为两段。
m=1就不用讨论了
m>1的时候
前半段为a1....an 前半段最优解 (u....u)
后半段an+1...am 后半段最优解为(v...v)
如果u≤v 那么该序列最优解为 (u....u,v ...v)
如果u>v 整个序列最优解为b1...bm
我们要证明这段b1=b2=..=bn=a序列的中位数w会最优。
可知bn<=u (如果大于的话。。那么前面全部变成u,不会更差),同理b (n+1)>=v;
那么我们需要证明当 bn<=w<=u 或 v<=w<=b(n+1)
(b1....bm)比 (w,w,w...w)差
换句话说,也就是说对于一段序列
假设他的最优解是 (u....u)。。。我们暂定他的一个解为b1...bn
当 u<=w<=b1 或者 bn<=w<=u的时候。。我们
决策(w....w)比(b1,b2,....bn)更优
证明  bn<=w<=u的情况 。。
用数学归纳法证明
当n=1的时候 。。u=a[1] 这个显然成立
当n>1、、、假设n-1成立 前n-1个数的中位数为w,那么我们把解变成(bn....bn)
由于bn>=b(n-1) 如果使得答案变得更差了,那么
b(n-1)<=bn<=w不成立。。也就是说bn>w又因为bn<=u 所以可以知道他的最优解为
(w,w...w,u,u...u)与(u,u,...u)矛盾
然后把bn改成u’, 由于 b1<=u'<=u由于它的函数图像是单峰的,所以u‘不会更差
同理  u<=w<=b1  也成立
回到之前的。a1...am的序列
由上面的证明可以知道最优解为(bn....bn,b(n+1)...b(n+1))
考虑一下该解的集合意义,设整个序列中位数为p那么让bn=b(n+1)=p可以得到最优解
(p.....p)为最优解


有了上面的理论依据。。就得出了一下算法

 

每次插入a[k]
前面的k-1个数有x个区间 ,每个区间为一个堆。
如果a[k]比前一个区间的中位数大。。则自己独立开出一个区间。。
如果比前一个区间中位数小。则插入前面的区间的堆中,同时比较x-1,和x区间如果
后者中位数小于前者的。那么合并两个堆。

昨晚看了算法导论= =斐波那契额堆各种乱。。。编程复杂度巨大。。
选择左偏树还是比较实在,编程复杂度低而且速度也很可观。

关于如何存区间的中位数
我们每个区间的堆存的是比中位数小的所有数。
该区间比它中位数还大的数必然不小于前一个区间的中位数。否则可以自己开一个区间。
然后当需要合并两个区间都为奇数,删掉堆顶元素。

 

 

一下代码是参考了论文中的代码后写出来的。。感觉好像。。

看看代码长度

简洁而不简单。