1112: [POI2008]砖块Klo

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

 

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

 
枚举区间,得到中位数,再得到操作数,所以我们需要一个数据结构支持插入,删除,查询rank,
所以用平衡树好了,同时维护区间的值。
  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<string>
  8 #include<map>
  9 #include<queue>
 10 #include<vector>
 11 #include<set>
 12 #define inf 9223372036854775807LL
 13 #define maxn 1000000+5
 14 #define maxm 10000+5
 15 #define eps 1e-10
 16 #define ll long long
 17 #define for0(i,n) for(int i=0;i<=(n);i++)
 18 #define for1(i,n) for(int i=1;i<=(n);i++)
 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 22 using namespace std;
 23 int read(){
 24     int x=0,f=1;char ch=getchar();
 25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 27     return x*f;
 28 }
 29 int n,m,k,rt,sz;
 30 ll tmp;
 31 ll ans=inf,sum1,sum2;
 32 int h[maxn],rnd[maxn],s[maxn],c[maxn][2],w[maxn];
 33 ll sum[maxn],v[maxn];
 34 void update(int k){
 35     s[k]=s[c[k][0]]+s[c[k][1]]+w[k];
 36     sum[k]=sum[c[k][0]]+sum[c[k][1]]+v[k]*w[k];
 37 }
 38 void rturn(int &k){
 39     int t=c[k][0];c[k][0]=c[t][1];c[t][1]=k;update(k);update(t);k=t;
 40 }
 41 void lturn(int &k){
 42     int t=c[k][1];c[k][1]=c[t][0];c[t][0]=k;update(k);update(t);k=t;
 43 }
 44 void insert(int &k,int x){
 45     if(!k){
 46         k=++sz;sum[k]=v[k]=x;
 47         w[k]=s[k]=1;rnd[k]=rand();
 48         return ;
 49     }
 50     s[k]++;sum[k]+=x;
 51     if(x==v[k])w[k]++;
 52     else if(x<v[k]){
 53         insert(c[k][0],x);
 54         if(rnd[c[k][0]]<rnd[k])
 55             rturn(k);
 56     }
 57     else{
 58         insert(c[k][1],x);
 59         if(rnd[c[k][1]]<rnd[k])
 60             lturn(k);
 61     }
 62 }
 63 void del(int &k,int x){
 64     if(!k)return ;
 65     if(x==v[k]){
 66         if(w[k]>1){
 67             w[k]--;s[k]--;sum[k]-=x;
 68             return ;
 69         }
 70         if(!(c[k][0]*c[k][1]))k=c[k][0]+c[k][1];
 71         else if(rnd[c[k][0]]<rnd[c[k][1]]){
 72             rturn(k);
 73             del(k,x);
 74         }
 75         else{
 76             lturn(k);
 77             del(k,x);
 78         }
 79         return ;
 80     }
 81     s[k]--;sum[k]-=x;
 82     if(x<v[k])del(c[k][0],x);
 83     else del(c[k][1],x);
 84 }
 85 void find(int k,int rk){
 86     if(!k)return ;
 87     if(rk>s[c[k][0]]&&rk<=s[c[k][0]]+w[k]){
 88         sum1+=(sum[c[k][0]]+(rk-s[c[k][0]]-1)*v[k]);
 89         sum2+=(sum[c[k][1]]+(s[c[k][0]]+w[k]-rk)*v[k]);
 90         tmp=v[k];
 91     }
 92     else if(rk<=s[c[k][0]]){
 93         sum2+=(sum[c[k][1]]+v[k]*w[k]);
 94         find(c[k][0],rk);
 95     }
 96     else{
 97         sum1+=(v[k]*w[k]+sum[c[k][0]]);
 98         find(c[k][1],rk-s[c[k][0]]-w[k]);
 99     }
100 }
101 void getans(){
102     sum1=sum2=0;
103     find(rt,m);
104     ll sum=(m-1)*tmp-sum1+sum2-(k-m)*tmp;
105     if(sum<ans)ans=sum;
106 }
107 int main(){
108     //freopen("input.txt","r",stdin);
109     //freopen("output.txt","w",stdout);
110     n=read();k=read();m=((k+1)>>1);
111     for1(i,n)
112         h[i]=read();
113     for1(i,k)
114         insert(rt,h[i]);
115     getans();
116     for(int i=k+1;i<=n;i++){
117         del(rt,h[i-k]);
118         insert(rt,h[i]);
119         getans();
120     }
121     printf("%lld",ans);
122     return 0;
123 }
View Code

 

posted @ 2016-07-09 11:22  HTWX  阅读(109)  评论(0编辑  收藏  举报