sequence(bzoj 1367)

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]
  考虑一个逆序的序列,z[i]=x(x是逆列的中位数)
  既然是这样那么我们就可以把整个序列化分成逆序的若干段,对于每段求中位数(正序的可看成num个逆序的)。
  维护中位数用左偏树,具体方法是始终保持堆中数的个数不大于原数个数的一半。
  至于改成上升的,把原序列t[i]-=i。

  PS:题解中的root[i]和堆中下标的关系把我看蒙了,所以这里说一下。
      代码中是建立了n个堆,然而不断合并,最终变成了tot个。
      root[i]表示第i个堆(合并后的)的堆顶是哪个元素。
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#define N 1000010
using namespace std;
int t[N],root[N],l[N],r[N],num[N],cnt[N],n,tot;
struct node{
    int l,r,dis,w;
};node heap[N];
int merge(int a,int b){
    if(a==0||b==0)return a+b;
    if(heap[a].w<heap[b].w)swap(a,b);
    heap[a].r=merge(heap[a].r,b);
    if(heap[heap[a].r].dis>heap[heap[a].l].dis)
        swap(heap[a].r,heap[a].l);
    heap[a].dis=heap[heap[a].r].dis+1;
    return a;
}
int pop(int a){
    return merge(heap[a].l,heap[a].r);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&t[i]),t[i]-=i;
    for(int i=1;i<=n;i++){
        ++tot;
        l[tot]=r[tot]=i;
        num[tot]=cnt[tot]=1;
        root[tot]=i;
        heap[i].dis=heap[i].l=heap[i].r=0;
        heap[i].w=t[i];

        while(tot>1&&heap[root[tot]].w<heap[root[tot-1]].w){
            --tot;
            root[tot]=merge(root[tot],root[tot+1]);
            num[tot]+=num[tot+1],cnt[tot]+=cnt[tot+1],r[tot]=r[tot+1];
            for(;cnt[tot]*2>num[tot]+1;--cnt[tot])
                root[tot]=pop(root[tot]);
        }
    }
    long long ans=0;
    for(int i=1;i<=tot;i++)
        for(int j=l[i],w=heap[root[i]].w;j<=r[i];j++)
            ans+=abs(t[j]-w);
    cout<<ans;
    return 0;
} 
时间: 2024-11-05 08:29:36

sequence(bzoj 1367)的相关文章

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(中位数+可并堆)

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]

【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

BZOJ 1367 [Baltic2004]sequence 可并堆

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

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是区间标

浅谈左偏树在OI中的应用

Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log(|A|)+\log(|B|)\),极限数据下显然是要T爆的. 所以我们考虑使用一种性价比最高的可并堆--左偏树,它的思想以及代码都挺简单而且效率也不错. 学习和参考自这里 What is Leftist Tree 左偏树,顾名思义就是像左偏的树,但是这样抽象的表述肯定是不符合我们学OI的人的背板子

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 3043: IncDec Sequence

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 578  Solved: 325[Submit][Status][Discuss] Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接

bzoj 3043: IncDec Sequence 模拟

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 248  Solved: 139[Submit][Status] Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接下来n行,每行一个