【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;
}
时间: 2024-10-22 13:00:03

【bzoj1367】[Baltic2004]sequence 可并堆的相关文章

【BZOJ-1367】sequence 可并堆+中位数

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 932  Solved: 348[Submit][Status][Discuss] Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 Source Solution 论文

可并堆试水--BZOJ1367: [Baltic2004]sequence

n<=1e6个数,把他们修改成递增序列需把每个数增加或减少的总量最小是多少? 方法一:可以证明最后修改的每个数一定是原序列中的数!于是$n^2$DP(逃) 方法二:把$A_i$改成$A_i-i$,变论文题:论文 大概证明是这样的:考虑合并两个区间的答案,假如一个区间答案是{u,u,u,--,u},另一个是{v,v,v,--,v},那合并之后,如果u<=v最优就{u,u,--,u,v,--,v}:如果u>v,假设最优是 {b1,b2,--,bn,bn+1,--,bm},那么一定有bn<

BZOJ1367 [Baltic2004]sequence

现学的左偏树...这可是道可并堆的好题目. 首先我们考虑z不减的情况: 我们发现对于一个区间[l, r],里面是递增的,则对于此区间最优解为z[i] = t[i]: 如果里面是递减的,z[l] = z[l + 1] = ... = z[r] = 这段数的中位数,不妨叫做w.(此处我们定义中位数为第(r - l + 1) / 2大的数,因为这并不影响结果) 而其实递增可以转化为每一段只有一个点,就等价于递减了. 那么我们把原数列分段,每段都是递减的,而每一段的z都是那段的中位数w.这样就找到了最优

BZOJ 1367 [Baltic2004]sequence 可并堆

题意:链接 方法:可并堆 解析: wzc讲的第二道可并堆?不这是第一道,然后之前他好像还讲了个双堆求中位数? 大概想想,是不是就是维护一个小根堆以及一个大根堆,之后每次来元素,比中位数大就加到小根堆,比中位数小就加到大根堆,之后如果两堆差超过了2,就往少的里加,之后元素多的堆里的堆顶元素是新中位数? 好像是吧我也没太听,不过自己YY这感觉像是对的? 反正我不会写堆 以上与本题无关 接下来说本题: 首先让我们这么想,如果一个递增序列,那么它的对应选取的序列就是其本身,对答案没有贡献,如果一个递减序

bzoj1367 [Baltic2004]sequence [左偏树]

新博客宣传一发http://shijieyywd.com/?p=73 Description 给定一个序列t1,t2,...,tn,求一个递增序列z1<z2<...<zn, 使得R=|t1?z1|+|t2?z2|+...+|tn?zn|的值最小.本题中,我们只需要求出这个最小的R值. Input 第1行为一个整数n(1<=n<=106), 第2行到第n + 1行,每行一个整数,第k + 1行为tk(0<=tk<=2?109). Output 一个整数R Sampl

bzoj 1367: [Baltic2004]sequence(中位数+可并堆)

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 935  Solved: 351 [Submit][Status][Discuss] Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18. R=13 Source [Submit]

【BZOJ1367】[Baltic2004]sequence 左偏树

[BZOJ1367][Baltic2004]sequence Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 题解:详见论文 然而本题要求z[i]严格递增,那就让所有t[i]-=i就好了 #include <cstdio> #include <cstring> #include <iostrea

【bzoj1367】[Baltic2004]sequence

2016-05-31 17:31:26 1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define ll long long 4 #define N 1000005 5 using namespace std; 6 int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 wh

bzoj 1367: [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 详细证明请看IOI2005国家集训队论文  黄源河 https://wenku.baidu.com/view/20e9ff18964b