zoukankan      html  css  js  c++  java
  • BZOJ 1367: [Baltic2004]sequence [可并堆 中位数]

    1367: [Baltic2004]sequence

    Time Limit: 20 Sec  Memory Limit: 64 MB
    Submit: 1111  Solved: 439
    [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


    这里是hyh的题解及严谨证明

    这里是Candy?的做法及证(瞎)明(猜):

    貌似可以在坐标系里画出来啊

    <好烦啊先不管了

    如果a递增,那就是0啊

    如果只能选一个纵坐标,那一定是a的中位数啊(反证应该谁都会吧)

    但本题给了我们更多的机会,往左可以多选几个比中位数小的点,往右可以选几个多的

    所以最优情况就应该是选了一个或多个递增的某个区间的中位数

    证(猜)毕(完)

    每加入一个点形成一个区间,与上一个区间比较,如果上一个区间的中位数大(那么就不满足递增了)就把这个点和上一个区间合并,继续让这个区间和上个区间比较

    维护区间中位数可以用左偏树,因为合并后中位数只会减小,所以维护一个大根堆,size>区间大小一半就弹出

    rt[]保存了每个区间用的左偏树的根

    <变成<=用到了常见技巧 -i

    注意:一开始记录区间l和r时写成了l[rt[p]]应该是l[p]

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define lc t[x].l
    #define rc t[x].r
    typedef long long ll;
    const int N=1e6+5,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n,a[N];
    struct node{
        int l,r,v,d,size;
        node(){l=r=v=d=size=0;}
    }t[N];  
    int sz;
    int Merge(int x,int y){
        if(x==0||y==0) return x|y;
        if(t[x].v<t[y].v) swap(x,y);
        rc=Merge(rc,y);
        t[x].size=t[lc].size+t[rc].size+1;
        if(t[lc].d<t[rc].d) swap(lc,rc);
        t[x].d=t[rc].d+1;
        return x;
    }
    inline int nw(int v){
        t[++sz].v=v;
        t[sz].size=1;
        return sz;
    }
    inline int top(int x){return t[x].v;}
    inline int size(int x){return t[x].size;}
    inline void pop(int &x){x=Merge(lc,rc);}
    ll ans;
    int rt[N],p,l[N],r[N],tot[N];
    void solve(){
        for(int i=1;i<=n;i++){
            rt[++p]=nw(a[i]);
            l[p]=r[p]=i;tot[p]=1;
            while(p-1&&top(rt[p-1])>top(rt[p])){
                rt[p-1]=Merge(rt[p-1],rt[p]);
                p--;
                r[p]=i;
                while(size(rt[p])>(r[p]-l[p]+2)/2) pop(rt[p]);
            }
        }
        for(int i=1;i<=p;i++)
            for(int j=l[i];j<=r[i];j++) ans+=abs(a[j]-top(rt[i]));
        printf("%lld",ans);
    }
     
    int main(){
        //freopen("in.txt","r",stdin);
        n=read();
        for(int i=1;i<=n;i++) a[i]=read()-i;
        t[0].d=-1;
        solve();
        return 0;
    }
  • 相关阅读:
    2020年终总结
    vi编辑器使用基本操作
    为什么Windows下重载Nginx配置不生效
    JAVA、C#中使用正则表达式替换字符串
    领域事件、集成事件、事件总线区别与关系
    asp.net core中使用Serilog以及自定义Enricher
    C语言----文件(高阶篇二十八)
    C语言----指针与一维数组(高阶篇二十七)
    C语言----位运算(进阶篇二十六)
    C语言----指针基础(进阶篇二十五)
  • 原文地址:https://www.cnblogs.com/candy99/p/6288123.html
Copyright © 2011-2022 走看看