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
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 }