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][Status][Discuss]

题解:中位数+可并堆

分情况讨论一下:

一个区间[l, r],递增的,则对于此区间最优解为z[i] = t[i];

一个区间[l,r] ,递减的,则z[l] = z[l + 1] = ... = z[r] = 这段数的中位数,不妨叫做w。(中位数为第(r - l + 1) / 2大的数),为什么是中位数呢,因为区间是递减的,我们要把他变成不下降的,最小的改动情况就是把他改成一个每个数都相同的序列,那么这就转化成了中位数问题,因为所有点到中位数的距离是最小的。但是我们要求的是上升序列而不是不下降序列,所以需要将将v[i]处理成v[i]-i。

那么这样就可以做了,对于递增的区间,我们可以把区间中的每一个数看成一个单独的堆,那么这个堆维护的中位数就是他本身。如果要加入一个数,我们可以把这个点先看成一个单独的堆,如果v[root[now]]<v[root[now]]也就是当前这个点,比他的前一个区间的中位数要小,但是我们要求他递增,那么这个问题又转换成了“一个区间[l,r]
,递减的,则z[l] = z[l + 1] = ... = z[r] = 这段数的中位数”这个问题,我们可以用可并堆来将两个合并到一起。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 1000003
using namespace std;
int n,m;
int v[N],l[N],r[N],R[N],L[N],size[N],tot[N],root[N],d[N];
int merge(int x,int y)
{
	if (!x) return y;
	if (!y) return x;
	if (v[x]<v[y]) swap(x,y);
	R[x]=merge(R[x],y);
	size[x]=size[L[x]]+size[R[x]]+1;
	if (d[L[x]]<=d[R[x]])  swap(L[x],R[x]);
	d[x]=d[R[x]]+1;
	return x;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&v[i]),v[i]=v[i]-i;
    int now=0;
    for (int i=1;i<=n;i++)
     {
     	now++;
     	root[now]=i;
        l[now]=r[now]=i; //所控制区间的左右端点
	    tot[now]=1;//当前堆维护的中位数控制的数的个数
        size[root[now]]=1;//堆中元素的个数
        while (now>1&&v[root[now-1]]>v[root[now]])
         {
         	now--;
         	r[now]=r[now+1]; tot[now]+=tot[now+1];
         	root[now]=merge(root[now],root[now+1]);
         	while (size[root[now]]*2>tot[now]+1)//保证堆顶元素是当前区间的中位数
         	 root[now]=merge(L[root[now]],R[root[now]]);
         }
     }
    long long ans=0;
    for (int i=1;i<=now;i++)
     for (int j=l[i];j<=r[i];j++)
      ans+=(long long)abs(v[j]-v[root[i]]);
    printf("%I64d\n",ans);
}
时间: 2024-11-10 01:16:47

bzoj 1367: [Baltic2004]sequence(中位数+可并堆)的相关文章

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

BZOJ 1367 [Baltic2004]sequence 可并堆

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

1367: [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 1090  Solved: 432 [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 [题解]: 详

【BZOJ 1367】 [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 631  Solved: 215 [Submit][Status] 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 左偏树. 详细题解(在P13). 这个题解求的z

【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

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1111  Solved: 439 [Submit][Status][Discuss] Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 学长论文:左偏树的特点及其应用 cnt是区间标

【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 [左偏树]

新博客宣传一发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

sequence(bzoj 1367)

Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 /* 思维很扭曲(反正我想不出来)的一道题. 先想想不下降的: 考虑一个正序的序列,z[i]=t[i] 考虑一个逆序的序列,z[i]=x(x是逆列的中位数) 既然是这样那么我们就可以把整个序列化分成逆序的若干段,对于每段求中位数(正序的可看成num个逆序的). 维护中位数用左偏树,