bzoj 1112 [POI2008]砖块Klo

 [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2196  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

 

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

 
题解:水水的一道题目,划水就可以过了。
   因为区间k固定,所以每次绝对是取中位数的,
   那么只需要一个数据结构,支持寻找中位数,插入,删除,
   求和,这些即可。
   
   那就是Treap瞎搞即可。
  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 
  7 #define ll long long
  8 #define ls tr[p].l
  9 #define rs tr[p].r
 10 #define N 100007
 11 using namespace std;
 12 const ll inf=2000000000000010;
 13 inline ll read()
 14 {
 15     ll x=0,f=1;char ch=getchar();
 16     while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
 17     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 ll n,sz,rt,ans,k;
 22 ll a[N];
 23 struct Node
 24 {
 25     ll l,r,val,siz,rnd,ct,sum;//记录左儿子,右儿子,点值,该子树大小,随机的值,该点值出现的次数。 
 26 }tr[N*10];//最多多少个节点,就开多少空间 
 27 
 28 inline int rand()
 29 {
 30     static ll seed = 2333;
 31     return seed = (ll)((((seed ^ 998244353) + 19260817ll) * 19890604ll) % 1000000007);
 32 }
 33 inline void update(ll p)
 34 {
 35     tr[p].siz=tr[ls].siz+tr[rs].siz+tr[p].ct;
 36     tr[p].sum=tr[ls].sum+tr[rs].sum+tr[p].ct*tr[p].val;
 37 }
 38 void lturn(ll &p)
 39 {
 40     ll t=tr[p].r;tr[p].r=tr[t].l;tr[t].l=p;
 41     update(t),update(p);p=t;
 42 }
 43 void rturn(ll &p)
 44 {
 45     ll t=tr[p].l;tr[p].l=tr[t].r;tr[t].r=p;
 46     tr[t].siz=tr[p].siz;update(p);p=t;
 47 }
 48 void ins(ll &p,ll x)
 49 {
 50     if (p==0)
 51     {
 52         p=++sz;
 53         tr[p].siz=tr[p].ct=1,tr[p].val=x,tr[p].sum=x,tr[p].rnd=rand();
 54         return;
 55     }
 56     tr[p].siz++;
 57     if (tr[p].val==x) tr[p].ct++;
 58     else if (x>tr[p].val)
 59     {
 60         ins(tr[p].r,x);
 61         if (tr[rs].rnd<tr[p].rnd) lturn(p);
 62     }else
 63     {
 64         ins(tr[p].l,x);
 65         if (tr[ls].rnd<tr[p].rnd) rturn(p);
 66     }
 67     update(p);
 68 }
 69 void del(ll &p,ll x)
 70 {
 71     if (p==0) return;
 72     if (tr[p].val==x)
 73     {
 74         if (tr[p].ct>1) tr[p].ct--,tr[p].siz--,tr[p].sum-=x;//如果有多个直接减一即可。
 75         else
 76         {
 77             if (ls==0||rs==0) p=ls+rs;//单节点或者空的话直接儿子移上来或者删去即可。
 78             else if (tr[ls].rnd<tr[rs].rnd) rturn(p),del(p,x);
 79             else lturn(p),del(p,x); 
 80         }
 81     }
 82     else if (x>tr[p].val) tr[p].siz--,del(rs,x),tr[p].sum-=x;
 83     else tr[p].siz--,del(ls,x),tr[p].sum-=x;
 84     update(p);
 85 }
 86 void solve(ll p,ll x,ll &sum,ll &num,ll &ge,ll &zhi)
 87 {
 88     if (tr[ls].siz>=x) solve(ls,x,sum,num,ge,zhi);
 89     else
 90     {
 91         x-=tr[ls].siz,sum+=tr[ls].sum,num+=tr[ls].siz;
 92         if (tr[p].ct>=x)
 93         {
 94             ge=tr[p].ct;
 95             zhi=tr[p].val;
 96             return;
 97         }
 98         x-=tr[p].ct,sum+=tr[p].val*tr[p].ct,num+=tr[p].ct;
 99         solve(rs,x,sum,num,ge,zhi);
100     }
101 }
102 int main()
103 {
104     freopen("fzy.in","r",stdin);
105     freopen("fzy.out","w",stdout);
106     
107     n=read(),k=read();
108     for (ll i=1;i<=k;i++)
109         a[i]=read(),ins(rt,a[i]);
110 //    cout<<tr[rt].val<<endl;    
111     ans=inf;
112     for (ll i=k+1;i<=n+1;i++)
113     {
114         ll x=0,y=0,z=0,d=0;
115         solve(rt,(k+1)/2,x,y,z,d);
116         //cout<<x<<" "<<y<<" "<<z<<" "<<d<<endl;
117         ll res=0;
118         res+=d*y-x;
119         res+=tr[rt].sum-x-z*d-d*(tr[rt].siz-y-z);
120         ans=min(ans,res);
121         if (i<=n)
122         {
123             del(rt,a[i-k]);
124             a[i]=read();
125             ins(rt,a[i]);
126         }
127     }
128     printf("%lld",ans);
129 }

 

posted @ 2017-12-19 15:08  Kaiser-  阅读(110)  评论(0编辑  收藏  举报