您的位置:首页 > 其它

bzoj 1112: [POI2008]砖块Klo treap

2016-12-07 19:08 369 查看

题意

给出n个数,每次操作可以让一个数+1或-1,求连续的m个数,使得他们变成相同的数的操作数最少。

n,m<=100000

分析

假设现在给出m个数,要想使得他们变成相同的数的操作数最少,显然要让他们都变成这个m个数的中位数。

知道了这个后我们就可以用一棵treap来暴力这个m个值,然后每次查找中位数即可。

第一次用c++写treap,感觉好虚啊,顺便去借鉴了一波黄学长的删除操作。话说黄学长的代码真心简洁明了啊%%%

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 100005
#define ll long long
using namespace std;

int n,m,a
,size,tot,root;
ll sum,ans;
struct tree{int size,val,in,l,r,k;ll s;}t
;

void updata(int x)
{
t[x].size=t[t[x].l].size+t[t[x].r].size+t[x].in;
t[x].s=t[t[x].l].s+t[t[x].r].s+(ll)t[x].in*t[x].val;
}

void rttl(int &x)
{
int y=t[x].r;
t[x].r=t[y].l;
t[y].l=x;
updata(x);
updata(y);
x=y;
}

void rttr(int &x)
{
int y=t[x].l;
t[x].l=t[y].r;
t[y].r=x;
updata(x);
updata(y);
x=y;
}

void ins(int &x,int val)
{
if (!x)
{
x=++tot;
t[x].val=t[x].s=val;t[x].size=t[x].in=1;t[x].k=rand();
return;
}
t[x].s+=val;t[x].size++;
if (t[x].val==val)
{
t[x].in++;
return;
}
if (val<t[x].val)
{
ins(t[x].l,val);
if (t[t[x].l].k<t[x].k) rttr(x);
}else
{
ins(t[x].r,val);
if (t[t[x].r].k<t[x].k) rttl(x);
}
}

void del(int &x,int val)
{
if (!x) return;
if (t[x].val==val)
{
if (t[x].in>1)
{
t[x].in--;t[x].size--;t[x].s-=val;return;
}
else if (t[x].l*t[x].r==0)
{
x=t[x].l+t[x].r;return;
}
else if (t[t[x].l].k<t[t[x].r].k)
{
rttr(x);del(t[x].r,val);
}
else
{
rttl(x);del(t[x].l,val);
}
}
else if (val<t[x].val) del(t[x].l,val);
else del(t[x].r,val);
updata(x);
}

int find(int x,int y)
{
if (t[t[x].l].size+1<=y&&t[t[x].l].size+t[x].in>=y)
{
sum+=t[t[x].l].s;size+=t[t[x].l].size;
return t[x].val;
}
if (t[t[x].l].size+t[x].in<y)
{
sum+=t[t[x].l].s+(ll)t[x].val*t[x].in;size+=t[t[x].l].size+t[x].in;
y-=t[t[x].l].size+t[x].in;
return find(t[x].r,y);
}else
{
return find(t[x].l,y);
}
}

int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
t[0].k=1e7;
for (int i=1;i<=m;i++)
ins(root,a[i]);
ll ans=1e17;
sum=size=0;
int x=find(root,(1+m)/2);
ans=min(ans,(ll)x*size-sum+t[root].s-sum-(ll)x*(m-size));
for (int i=m+1;i<=n;i++)
{
del(root,a[i-m]);
ins(root,a[i]);
sum=size=0;
int x=find(root,(1+m)/2);
ans=min(ans,(ll)x*size-sum+t[root].s-sum-(ll)x*(m-size));
}
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: