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\n",ans);
    return 0;
}
posted @ 2014-09-08 22:48  zrt  阅读(294)  评论(0编辑  收藏  举报

Never stop,never ending!