【bzoj1367】[Baltic2004]sequence 可并堆

题目描述

输入

输出

一个整数R

样例输入

7
9
4
8
20
14
15
18

样例输出

13


题解

可并堆,黄源河《左偏树的特点及其应用Page 13例题原题

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
using namespace std;
int a[N] , root[N] , l[N] , r[N] , d[N] , w[N] , tot , si[N] , lp[N] , rp[N];
int merge(int x , int y)
{
	if(!x) return y;
	if(!y) return x;
	if(w[x] < w[y]) swap(x , y);
	si[x] += si[y];
	r[x] = merge(r[x] , y);
	if(d[l[x]] < d[r[x]]) swap(l[x] , r[x]);
	d[x] = d[r[x]] + 1;
	return x;
}
int main()
{
	int n , i , j , p = 0;
	long long ans = 0;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , a[i] -= i;
	for(i = 1 ; i <= n ; i ++ )
	{
		root[++p] = ++tot , w[tot] = a[i] , si[tot] = 1 , lp[p] = rp[p] = i;
		while(p > 1 && w[root[p]] < w[root[p - 1]])
		{
			p -- , root[p] = merge(root[p] , root[p + 1]) , rp[p] = rp[p + 1];
			while(2 * si[root[p]] > rp[p] - lp[p] + 2) root[p] = merge(l[root[p]] , r[root[p]]);
		}
	}
	for(i = 1 ; i <= p ; i ++ )
		for(j = lp[i] ; j <= rp[i] ; j ++ )
			ans += (long long)abs(w[root[i]] - a[j]);
	printf("%lld\n" , ans);
	return 0;
}

 

 

posted @ 2017-05-18 07:33  GXZlegend  阅读(376)  评论(0编辑  收藏  举报