您的位置:首页 > 其它

【bzoj1367】左偏树

2015-05-30 09:09 225 查看


1367: [Baltic2004]sequence


Description



这道题的结论证明参见 论文

对于求不下降序列 最后的做法就是:维护几段连续的序列,使它们的中位数不下降


然而转化到递增序列,我们只需要将每个数读进来的之后减去它的下标就可以了


所以我们对于每一段已求好的序列,既要维护它的中位数,又要支持合并

因为我们合并的前提是:中位数(i)>中位数(i+1),那么对于合并后的i而言,中位数肯定是不升的


根据这个性质我们又可以用可并堆了,堆顶元素表示该序列中的中位数


当堆的元素个数*2>序列长度+1的时候就可以弹出堆顶

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define RepE(i, x) for (int i = pos[x]; i; i = g[i].nex)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define u t[x]
#define v t[y]
#define Lc t[ u.lc ]
#define Rc t[ u.rc ]
using namespace std;
typedef long long LL;
const int N = 1000005;
struct arr { int lc, rc, vl, d; } t
;
int n, ro
, l
, s
, a
, m, l1
, r1
;
LL ans;
int Merge(int x, int y) {
if (!x || !y) return x + y;
if (u.vl < v.vl) swap(x, y);
u.rc = Merge(u.rc, y);
if (Rc.d > Lc.d) swap(u.rc, u.lc);
u.d = Rc.d + 1;
return x;
}
int Del(int x) {
return Merge(u.lc, u.rc);
}
int main()
{
scanf ("%d", &n);
Rep(i, 1, n) {
scanf ("%d", &a[i]), a[i] -= i;
}
Rep(i, 1, n) {
t[ro[++ m] = i].vl = a[i], l[m] = s[m] = 1, l1[m] = r1[m] = i;
while (m > 1 && t[ ro[m-1] ].vl > t[ ro[m] ].vl) {
l[m-1] = l[m] + l[m-1], s[m-1] += s[m];
ro[m - 1] = Merge(ro[m], ro[m-1]);
m --, r1[m] = i;
while (l[m] > (s[m] + 1) / 2) ro[m] = Del(ro[m]), l[m] --;
}
}
Rep(i, 1, m) {
int k = t[ ro[i] ].vl;
Rep(j, l1[i], r1[i]) {
ans += abs(a[j] - k);
}
}
printf("%lld\n", ans);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: