BZOJ1112: [POI2008]砖块Klo Treap

BZOJ 1112: [POI2008]砖块Klo

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1701   Solved: 597

题解:
对于一个长度为K的区间,把这个区间内的砖块的高度都变成中位数是最优的。
维护一个平衡树:保持只有K个节点,支持插入删除元素,同时维护子树节点个数、 子树权值和。
每次在树中查询第K/2大元素,同时计算权值比其大和权值比其小的所有节点的权值和
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const LL N=100005;
const LL inf=1000000000000LL;
int n,K,a[N],root;
LL sum[N],w[N],v[N],ans=inf,now,tmp;
int siz[N],ls[N],rs[N],rnd[N];
void Pushup(LL x)
{
	siz[x]=siz[ls[x]]+siz[rs[x]]+w[x];
	sum[x]=sum[ls[x]]+sum[rs[x]]+w[x]*v[x];
}
void lx(int &x)
{
	int t=rs[x];
	rs[x]=ls[t],ls[t]=x;
	Pushup(x),Pushup(t);
	x=t;
}
void rx(int &x)
{
	int t=ls[x];
	ls[x]=rs[t],rs[t]=x;
	Pushup(x),Pushup(t);
	x=t;
}
int cnt;
void Ins(int &x,int p)
{
	if(!x)
	{
		x=++cnt,v[x]=p,sum[x]=p,w[x]=1,siz[x]=1,rnd[x]=rand();
		return;
	}
	if(v[x]==p) w[x]++;
	else if(p<v[x]){Ins(ls[x],p);if(rnd[ls[x]]>rnd[x]) rx(x);}
	else {Ins(rs[x],p);if(rnd[rs[x]]>rnd[x]) lx(x);}
	Pushup(x);
}
void Del(int &x,int p)
{
	if(v[x]==p)
    {
        if(w[x]>1) w[x]--;
        else if(ls[x]*rs[x]==0) x=ls[x]+rs[x];
        else if(rnd[ls[x]]<rnd[rs[x]]) lx(x),Del(x,p);
        else rx(x),Del(x,p);
 	}
 	else if(p<v[x]) Del(ls[x],p);
 	else Del(rs[x],p);
 	Pushup(x);
}
void find(int x,int k)
{
	if(k<=siz[ls[x]])
	{
		now+=sum[x]-sum[ls[x]];
		find(ls[x],k);
	}
	else if(k<=siz[ls[x]]+w[x])
	{
        now+=sum[rs[x]]+(siz[ls[x]]+w[x]-k)*v[x];
		now-=sum[ls[x]]+(k-siz[ls[x]])*v[x];
		tmp=v[x];
		return;
	}
	else
	{
		now-=sum[x]-sum[rs[x]];
		find(rs[x],k-(siz[x]-siz[rs[x]]));
	}
}
LL Query()
{
	int pos=(K+1)>>1;
	now=0;
	find(root,pos);
	return (pos*2-K)*tmp+now;
}
int main()
{
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	int j=1;
	for(int i=1;j<=n;i++)
	{
		while(j<=n&&j<=i+K-1) Ins(root,a[j]),j++;
		ans=min(ans,Query());
		Del(root,a[i]);
	}
	printf("%lld",ans);
}


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

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

Source

[Submit][Status][Discuss]
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值