【BZOJ 1112】 [POI2008]砖块Klo

来源:互联网 发布:php身份证号码验证 编辑:程序博客网 时间:2024/04/27 11:14

1112: [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1177  Solved: 392
[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

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


splay。


要让连续k个砖高度相同,让他们都变成中位数的高度最优,因此我们枚举每一个长度为k的区间,求中位数。


所以问题变成了支持插入删除,求一个序列的中位数(区间第k大),直接splay即可。


#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#define inf 1000005#define LL long longusing namespace std;int n,k,kk,root,tot,h[100000+5];struct splay{int l,r,size,data,fa;LL sum;}a[100000+5];void Push_up(int x){a[x].size=a[a[x].l].size+a[a[x].r].size+1;a[x].sum=a[a[x].l].sum+a[a[x].r].sum+a[x].data;}void zig(int x){int y=a[x].fa,z=a[y].fa;a[x].fa=z,a[y].fa=x;a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y;if (y==a[z].l) a[z].l=x;else a[z].r=x;Push_up(y);}void zag(int x){int y=a[x].fa,z=a[y].fa;a[x].fa=z,a[y].fa=x;a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y;if (y==a[z].l) a[z].l=x;else a[z].r=x;Push_up(y);}void Splay(int x,int s){while (a[x].fa!=s){int y=a[x].fa,z=a[y].fa;if (z==s){if (x==a[y].l) zig(x);else zag(x);break;}if (y==a[z].l){if (x==a[y].l) zig(y),zig(x);else zag(x),zig(x);}else{if (x==a[y].r)zag(y),zag(x);else zig(x),zag(x);}}Push_up(x);if (!s) root=x;}int Search(int w){int x=root,ans;while (x){ans=x;//a[x].size++,a[x].sum+=w;if (a[x].data>=w) x=a[x].l;else x=a[x].r;}return ans;}void Insert(int w){if (!root){a[++tot].fa=0,a[tot].size=1,a[tot].data=a[tot].sum=w,root=tot;return;}int x=Search(w);tot++;a[tot].data=a[tot].sum=w,a[tot].fa=x,a[tot].size=1;if (a[x].data>=w) a[x].l=tot;else a[x].r=tot;Splay(tot,0);}int Findkth(int x,int k){if (a[a[x].l].size+1==k) return x;int l=a[a[x].l].size;if (k<=l) return Findkth(a[x].l,k);return Findkth(a[x].r,k-l-1);}int Findw(int x,int w){if (a[x].data==w) return x;if (w>a[x].data) return Findw(a[x].r,w);return Findw(a[x].l,w);}void Delete(int w){int x=Findw(root,w);Splay(x,0);int k=a[a[x].l].size+1;int pre=Findkth(root,k-1),ne=Findkth(root,k+1);Splay(pre,0),Splay(ne,root);a[ne].l=0;Splay(ne,0);}LL Get(){Splay(Findkth(root,kk),0);return 1LL*a[root].data*(a[a[root].l].size-1)-(a[a[root].l].sum+1)+   a[a[root].r].sum-inf-1LL*a[root].data*(a[a[root].r].size-1);}int main(){    scanf("%d%d",&n,&k);root=0;Insert(-1),Insert(inf);for (int i=1;i<=n;i++)scanf("%d",&h[i]);LL ans;for (int i=1;i<=k;i++)Insert(h[i]);kk=(k+1)/2+1;ans=Get();for (int i=k+1;i<=n;i++){Delete(h[i-k]);Insert(h[i]);ans=min(ans,Get());}cout<<ans<<endl;return 0;}


1 0