bzoj1112【poi2008】砖块klo

1112: [POI2008]砖块Klo

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

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

Source




我们发现当连续k柱的最终高度为中位数时总次数最小,那么问题就转化为求所有长度为k的连续子序列的中位数,显然可以用平衡树解决。其他的具体过程大家脑补一下吧…




#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define MAXN 100100
#define INF 1000000000000
#define pa pair<int,int>
using namespace std;
struct tree_type
{
	int l,r,s,v,w;
	LL sum,rnd;
}t[MAXN];
int a[MAXN],n,p,q,tot=0,root=0;
LL m,ans=INF;
inline int read()
{
	int ret=0,flag=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
	return ret*flag; 
}
inline void pushup(int k){t[k].s=t[t[k].l].s+t[t[k].r].s+t[k].w;t[k].sum=t[t[k].l].sum+t[t[k].r].sum+t[k].w*t[k].v;}
inline void rturn(int &k){int tmp=t[k].l;t[k].l=t[tmp].r;t[tmp].r=k;t[tmp].s=t[k].s;t[tmp].sum=t[k].sum;pushup(k);k=tmp;}
inline void lturn(int &k){int tmp=t[k].r;t[k].r=t[tmp].l;t[tmp].l=k;t[tmp].s=t[k].s;t[tmp].sum=t[k].sum;pushup(k);k=tmp;}
inline void ins(int &k,int x)
{
	if (!k){k=++tot;t[k].s=t[k].w=1;t[k].sum=t[k].v=x;t[k].l=t[k].r=0;t[k].rnd=rand();return;}
	t[k].s++;t[k].sum+=x;
	if (t[k].v==x) t[k].w++;
	else if (t[k].v>x){ins(t[k].l,x);if (t[t[k].l].rnd<t[k].rnd) rturn(k);}
	else{ins(t[k].r,x);if (t[t[k].r].rnd<t[k].rnd) lturn(k);}
}
inline void del(int &k,int x)
{
	if (t[k].v==x)
	{
		if (t[k].w>1){t[k].s--;t[k].w--;t[k].sum-=x;}
		else if (!t[k].l||!t[k].r) k=t[k].l+t[k].r;
		else if (t[t[k].l].rnd<t[t[k].r].rnd){rturn(k);del(k,x);}
		else{lturn(k);del(k,x);}
		return;
	}
	t[k].s--;t[k].sum-=x;
	if (x<t[k].v) del(t[k].l,x);
	else del(t[k].r,x);
}
inline int getans(int k,int x)
{
	int ln=t[t[k].l].s;
	if (ln<x&&ln+t[k].w>=x){m+=t[t[k].l].sum+(x-ln)*t[k].v;return t[k].v;}
	else if (ln>=x) return getans(t[k].l,x);
	else{m+=t[t[k].l].sum+t[k].w*t[k].v;return getans(t[k].r,x-ln-t[k].w);}
}
inline void calc()
{
	m=0;
	LL tmp=getans(root,q);
	LL now=t[root].sum-m-tmp*(p-q)+tmp*q-m;
	ans=min(ans,now);
}
int main()
{
	n=read();p=read();q=p/2+1;
	F(i,1,n) a[i]=read();
	F(i,1,p) ins(root,a[i]);
	calc();
	F(i,p+1,n)
	{
		ins(root,a[i]);
		del(root,a[i-p]);
		calc();
	}
	printf("%lld\n",ans);
}


你可能感兴趣的:(bzoj)