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

    1112: [POI2008]砖块Klo

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2194  Solved: 787
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

    最小的动作次数

    Sample Input

    5 3
    3
    9
    2
    3
    1

    Sample Output

    2

    HINT

    原题还要求输出结束状态时,每柱砖的高度.本题略去.

    Source

    我们知道对于一个长度为k的序列,我们要花费最少的操作数就是把它们全部变为中位数

    不要问我为什么,自己脑补一下即可

    这时候我们就要拿出Treep去维护插入了删除操作,并查询区间中位数

    我们不断维护一个长度为k的序列,每次往后移一位,把i-k删除,把i加入

    最后算出花费即可   注意开longlong 坑死我了

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0;int f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int MAXN=1e5+10;
    int h[MAXN],n,cnt=0,tmp,root,m,k;
    ll ans,sum1,sum2;
    struct tree{
        int son[2],rnd,weight,siz;
        ll sum,v;
    }T[MAXN];
    inline void push_up(int root){
        T[root].siz=T[T[root].son[0]].siz+T[T[root].son[1]].siz+T[root].weight;
        T[root].sum=T[T[root].son[0]].sum+T[T[root].son[1]].sum+T[root].weight*T[root].v;
    }
    inline void leftrote(int &root){
        int x=T[root].son[1];T[root].son[1]=T[x].son[0];
        T[x].son[0]=root;push_up(root);push_up(x);root=x;
    }
    inline void rightrote(int &root){
        int x=T[root].son[0];T[root].son[0]=T[x].son[1];
        T[x].son[1]=root;push_up(root);push_up(x);root=x;
    }
    inline void insert(int &root,int vv){
        if(root==0){
            root=++cnt;T[root].v=T[root].sum=vv;
            T[root].weight=T[root].siz=1;
            T[root].rnd=rand();return;
        }
        T[root].sum+=vv;T[root].siz++;
        if(vv==T[root].v){
            T[root].weight++;
        }
        else if(vv<T[root].v){
            insert(T[root].son[0],vv);
            if(T[T[root].son[0]].rnd<T[root].rnd) rightrote(root);
        }
        else{
            insert(T[root].son[1],vv);
            if(T[T[root].son[1]].rnd<T[root].rnd) leftrote(root);
        }
    }
    inline void del(int &root,int vv){
        if(!root) return;
        if(T[root].v==vv){
            if(T[root].weight>1){
                T[root].weight--;T[root].sum-=vv;T[root].siz--;return;
            }
            if(T[root].son[0]*T[root].son[1]==0) root=T[root].son[0]+T[root].son[1];
            else if(T[T[root].son[0]].rnd<T[T[root].son[1]].rnd) {rightrote(root);del(root,vv);}
            else {leftrote(root);del(root,vv);}
        }
        else if(vv>T[root].v){
            T[root].siz--;T[root].sum-=vv;del(T[root].son[1],vv);
        }
        else{
            T[root].siz--;T[root].sum-=vv;del(T[root].son[0],vv);
        }
    }
    inline void find(int root,int rank){
        if(!root) return;
        if(rank>T[T[root].son[0]].siz&&rank<=T[T[root].son[0]].siz+T[root].weight){  
            sum1+=(T[root].v*(rank-T[T[root].son[0]].siz-1)+T[T[root].son[0]].sum);
            sum2+=T[root].v*(T[root].weight+T[T[root].son[0]].siz-rank)+T[T[root].son[1]].sum;
            tmp=T[root].v;
        }
        else if(rank<=T[T[root].son[0]].siz){
            sum2+=(T[root].weight*T[root].v)+T[T[root].son[1]].sum;
            find(T[root].son[0],rank);
        }
        else{
            sum1+=(T[root].weight*T[root].v)+T[T[root].son[0]].sum;
            find(T[root].son[1],rank-T[T[root].son[0]].siz-T[root].weight);
        }
    }
    inline void getans(){
        sum1=sum2=0;
        find(root,m);
        //cout<<tmp<<' '<<sum1<<' '<<sum2<<endl;
        ll t=1LL*(m-1)*tmp-sum1+sum2-1LL*(k-m)*tmp;
        ans=min(ans,t);
    }
    int main(){
        //freopen("All.in","r",stdin);
        //freopen("zh.out","w",stdout);
        n=read();k=read();m=(k+1)>>1;
        for(int i=1;i<=n;i++){
            h[i]=read();
        }
        ans=9000000000000;
        for(int i=1;i<=k;i++){
            insert(root,h[i]);
        }
        getans();
        for(int i=k+1;i<=n;i++){
            del(root,h[i-k]);insert(root,h[i]);
            getans();
        }
        cout<<ans<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    落花美眷,终究抵不过逝水流年,回忆我的2016,展望2017。
    如何对于几百行SQL语句进行优化?
    基于.NET Socket API 通信的综合应用
    数据库备份定期删除程序的开发。
    如何开发应用程序将客户服务器数据库的备份,下载到本地的云服务上?
    从大公司做.NET 开发跳槽后来到小公司的做.NET移动端微信开发的个人感慨
    asp.net mvc entity framework 数据库 练习(一)
    ASP.NET CORE小试牛刀:干货(完整源码)
    [开源].NET数据库访问框架Chloe.ORM
    SqlBulkCopy简单封装,让批量插入更方便
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/8063737.html
Copyright © 2011-2022 走看看