【bzoj1367】左偏树

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[N];
int n, ro[N], l[N], s[N], a[N], m, l1[N], r1[N];
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值