您的位置:首页 > 产品设计 > UI/UE

bzoj1367 sequence

2017-05-30 17:41 197 查看
因为每个数的绝对大小是没有意义的,我么只关心它们之间的差,所以可以把每个位置的值减掉下标,把问题转化成求不降序列。可以把考虑合并区间的答案,如果左边一段的答案是全变成x,右边一段是全变成y,那么如果u>v,整段区间的答案是整段的中位数。否则维持原状就可以。

于是我们可以从左往右扫描,用一个栈来维护,栈中每段区间的答案都是中位数,且答案递增。新加入一个数先看成单独的一个区间,然后不停地向左合并。我们需要一个数据结构支持维护中位数和区间合并。用左偏树维护最小的⌊n+12⌋个元素的大根堆就可以了。

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=1000010;
int rd()
{
int x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
int a[maxn],root[maxn],sta[maxn],lson[maxn],rson[maxn],height[maxn],size[maxn],n,top;
int merge(int u,int v)
{
if ((LL)u*v==0) return u+v;
if (a[u]<a[v]) swap(u,v);
rson[u]=merge(rson[u],v);
if (height[lson[u]]<height[rson[u]]) swap(lson[u],rson[u]);
height[u]=height[rson[u]]+1;
size[u]=size[lson[u]]+size[rson[u]]+1;
return u;
}
int main()
{
//freopen("in","r",stdin);
LL ans=0;
n=rd();
for (int i=1;i<=n;i++) a[i]=rd()-i;
for (int i=1;i<=n;i++)
{
sta[++top]=i;
size[i]=height[i]=1;
root[top]=i;
while (top>1&&a[root[top-1]]>=a[root[top]])
{
root[top-1]=merge(root[top-1],root[top]);
sta[top-1]=sta[top];
top--;
while (size[root[top]]>(sta[top]-sta[top-1]+1)/2)
root[top]=merge(lson[root[top]],rson[root[top]]);
}
}
for (int i=1;i<=top;i++)
for (int j=sta[i-1]+1;j<=sta[i];j++)
ans+=abs(a[j]-a[root[i]]);
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: