您的位置:首页 > 其它

【bzoj 1112】砖块Klo(权值线段树)

2018-02-28 18:27 344 查看
传送门biu~

对于连续的k柱,如果想要让它们变成一样高的,显然把它们都转化成这k柱高度的中位数可以使操作次数最小。在权值线段树上查询中位数并计算。

#include<bits/stdc++.h>
using namespace std;
const int inf=1000000;
int n,k,a[100005];
long long ans=1LL<<60;
struct Node{
Node *ch[2];
int siz;
long long sum;
Node();
inline void maintain(){
siz=ch[0]->siz+ch[1]->siz;
sum=ch[0]->sum+ch[1]->sum;
}
}*null=new Node,*root=null;
Node :: Node(){
ch[0]=ch[1]=null;
siz=sum=0;
}
void add(Node *&o,int l,int r,int x,int v){
if(o==null) o=new Node;
if(l==r){
o->siz+=v;  o->sum+=x;
return;
}
int mid=l+r>>1;
if(abs(x)<=mid) add(o->ch[0],l,mid,x,v);
else    add(o->ch[1],mid+1,r,x,v);
o->maintain();
}
int Kth(Node *o,int l,int r,int k){
if(l==r)    return l;
int mid=l+r>>1;
if(o->ch[0]->siz>=k)    return Kth(o->ch[0],l,mid,k);
else    return Kth(o->ch[1],mid+1,r,k-o->ch[0]->siz);
}
long long Query(Node *o,int l,int r,int p){
if(o==null)     return 0;
if(r<=p || l>p) return abs(o->sum-1ll*p*o->siz);
int mid=l+r>>1;
return Query(o->ch[0],l,mid,p)+Query(o->ch[1],mid+1,r,p);
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)   scanf("%d",&a[i]);
for(int i=1;i<=n;++i){
add(root,0,inf,a[i],1);
if(i-k>0)   add(root,0,inf,-a[i-k],-1);
if(i<k) continue;
int p=Kth(root,0,inf,(k+1)/2);
ans=min(ans,Query(root,0,inf,p));
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: