【BZOJ 1367】 [Baltic2004]sequence

1367: [Baltic2004]sequence

Time Limit: 20 Sec   Memory Limit: 64 MB
Submit: 631   Solved: 215
[ Submit][ Status]

Description

Input

Output

一个整数R

Sample Input

7
9
4
8
20
14
15
18

Sample Output

13

HINT

所求的Z序列为6,7,8,13,14,15,18.
R=13



左偏树。


详细题解(在P13)。


这个题解求的z是不减的,要求单增的话只要把a[i]减i再算即可。


很巧妙的是用左偏树来合并两个区间的中位数。


根据题解,前一个区间的中位数大于后一个区间的中位数,合并之后中位数只会变小,因此先把两个对合并(大根堆),然后把最大的一个个除去,最后剩下一半即可,最大的那个就是中位数。


一定要注意,这里的“一半”一定要向上取整!!因为如果两个区间原本都是3个,向下取整都变成1个,合并之后6个只剩下2个了。。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define M 1050000
using namespace std;
int n,a[M],root[M],l[M],r[M],w[M],tot=0,cnt=0;
struct Ltree
{
	int size,l,r,dis,v;
}t[M];
void read(int &tmp)
{
	tmp=0;
	char ch=getchar();
	int fu=1;
	for (;ch<'0'||ch>'9';ch=getchar())
		if (ch=='-') fu=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())
		tmp=tmp*10+ch-'0';
	tmp*=fu;
}
int New_heap(int x)
{
	t[x].v=a[x];
	t[x].l=t[x].r=t[x].dis=0;
	t[x].size=1;
	return x;
}
int Merge(int x,int y)
{
	if ((!x)||(!y)) return x+y;
	if (t[x].v<t[y].v)
		swap(x,y);
	t[x].size+=t[y].size;
	t[x].r=Merge(t[x].r,y);
	if (t[t[x].l].dis<t[t[x].r].dis)
		swap(t[x].l,t[x].r);
	t[x].dis=t[t[x].r].dis+1;
	return x;
}
int Del(int x)
{
	return Merge(t[x].l,t[x].r);
}
int main()
{
	read(n);
	for (int i=1;i<=n;i++)
		read(a[i]),a[i]-=i;
	tot=0;
	t[0].dis=-1;
	for (int i=1;i<=n;i++)
	{
		root[++tot]=New_heap(i);
		w[tot]=a[i];
		l[tot]=r[tot]=i;
		while (tot>1&&w[tot-1]>w[tot])
		{
			tot--;
			r[tot]=r[tot+1];
			root[tot]=Merge(root[tot],root[tot+1]);
			int x=(r[tot]-l[tot]+2)/2;
			while (t[root[tot]].size>x)
				root[tot]=Del(root[tot]);
			w[tot]=t[root[tot]].v;
		}
	}
	long long ans=0LL;
	for (int i=1;i<=tot;i++)
		for (int j=l[i];j<=r[i];j++)
			ans+=abs(a[j]-w[i]);
	printf("%lld\n",ans);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值