zoukankan      html  css  js  c++  java
  • BZOJ 1112: [POI2008]砖块Klo

    Description

    N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

    Input

    第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

    题解:

    如果确定了将区间[l,r]变成一样的,那么变成中位数需要的操作次数最少。

    可以用平衡树维护,支持查询第k大、查询小于k大数的和、查询大于k大数的和,利用这些可以快速的求出答案。

    复杂度`O(nlogn)`。注意开LL。

    代码:

    (平衡树写的渣。)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    //by zrt
    //problem:
    using namespace std;
    typedef long long LL;
    const int inf(0x3f3f3f3f);
    const double eps(1e-9);
    LL n,k;
    LL a[100005];
    LL num[100005],sum[100005],ls[100005],rs[100005],val[100005],fa[100005],siz[100005];
    inline void upd(int o){
        siz[o]=siz[ls[o]]+siz[rs[o]]+num[o];
        sum[o]=num[o]*val[o]+sum[ls[o]]+sum[rs[o]];
    }
    inline void zig(int x){
        int y=fa[x];
        if(rs[x]) ls[y]=rs[x],fa[rs[x]]=y;
        else ls[y]=0;
        fa[x]=fa[y];
        if(fa[y]){
            if(ls[fa[y]]==y) ls[fa[y]]=x;else rs[fa[y]]=x;
        }
        fa[y]=x;rs[x]=y;
        upd(y);
    }
    inline void zag(int x){
        int y=fa[x];
        if(ls[x]) rs[y]=ls[x],fa[ls[x]]=y;
        else rs[y]=0;
        fa[x]=fa[y];
        if(fa[y]){
            if(ls[fa[y]]==y) ls[fa[y]]=x;else rs[fa[y]]=x;
        }
        fa[y]=x;ls[x]=y;
        upd(y);
    }
    int root;
    inline void splay(int x,int z){
        while(fa[x]!=z){
            int y=fa[x];
            if(fa[y]==z){
                if(ls[y]==x) zig(x);
                else zag(x);
            }else{
                if(ls[fa[y]]==y){
                    if(ls[y]==x){
                        zig(y),zig(x);
                    }else{
                        zag(x);zig(x);
                    }
                }else{
                    if(ls[y]==x){
                        zig(x),zag(x);
                    }else{
                        zag(y),zag(x);
                    }
                }
            }
        }
        if(!z) root=x;
        upd(x);
    }
    int c;
    inline void insert(LL x){
        int o=root;
        int f=0;
        while(o){
            f=o;
            if(val[o]==x){
                num[o]++;
                splay(o,0);
                return;
            }
            if(x<val[o]){
                o=ls[o];
            }else{
                o=rs[o];
            }
        }
        o=++c;
        if(f){
            if(x<val[f]){
                ls[f]=o;
            }else{
                rs[f]=o;
            }
        }else root=o;
        fa[o]=f;
        val[o]=x;
        num[o]=1;
        splay(o,0);
    }
    inline void del(LL x){
        int o=root;
        while(1){
            if(val[o]==x){
                num[o]--;
                splay(o,0);
                return;
            }
            if(x<val[o]){
                o=ls[o];
            }else o=rs[o];
        }
    }
    inline void ask(int k){
        int o=root;
        while(1){
            if(siz[ls[o]]>=k) {
                o=ls[o];continue;
            }
            if(siz[ls[o]]+num[o]>=k) {
                splay(o,0);return;
            }else{
                k-=siz[ls[o]]+num[o];
                o=rs[o];
            }
        }
    }
    LL ans;
    int main(){
        #ifdef LOCAL
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
        #endif
        ans=inf*1LL*1000000;
        scanf("%lld%lld",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        for(int i=1;i<k;i++){
            insert(a[i]);
        }
        for(int i=k;i<=n;i++){
            if(i>k){
                del(a[i-k]);
            }
            insert(a[i]);
            ask((k+1)/2);
            LL aim=val[root];
            ans=min(ans,siz[ls[root]]*aim-sum[ls[root]]+sum[rs[root]]-siz[rs[root]]*aim);
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    加法的位运算实现
    C++装饰器模式
    字符串类型的相互转换
    手算CRC及其实现
    Linux下搭建C/C++编程环境
    Deepin Linux 实体机安装
    Atom + Texlive 配置 Latex 环境
    有关字符串的算法(KMP,Manacher,BM)陆续补充
    Linux 下大文件分割与合并
    Ubuntu /目录满,发现是docker image 太多解决办法
  • 原文地址:https://www.cnblogs.com/zrts/p/bzoj1112.html
Copyright © 2011-2022 走看看