【BZOJ2216】[Poi2011]Lightning Conductor 决策单调性

【BZOJ2216】[Poi2011]Lightning Conductor

Description

已知一个长度为n的序列a1,a2,...,an。
对于每个1<=i<=n,找到最小的非负整数p满足 对于任意的j, aj < = ai + p - sqrt(abs(i-j))

Input

第一行n,(1<=n<=500000)
下面每行一个整数,其中第i行是ai。(0<=ai<=1000000000)

Output

n行,第i行表示对于i,得到的p

 

Sample Input

6
5
3
2
4
2
4

Sample Output

2
3
5
3
5
4

题解:决策单调性不只是斜率优化~

p>=aj-ai+sqrt(abs(i-j)),有绝对值怎么办?拆开讨论两边就行。

你会发现,sqrt函数的增长是越来越慢的,也就意味着如果存在i<j<k,且对于k来说j比i更优,那么之后的i再也不会比j优了。我们想找到的,就是当前节点最远能更新到哪个点。

不难发现,每个点能做出贡献的区间是一段连续的区间(可能为空)。我们可以用双向队列来找出每个点能作用的区间的左右端点lp和rp,具体方法:

1.枚举到当前点i时,先更新i的答案,然后将队首的lp改为i,如果队首lp>rp,则弹出队首。
2.如果队列不为空,且i对于n不如队尾优,说明i永远干不掉队尾,则不将i加入队列。
否则,如果i对于lp[队尾]比队尾更优,则弹出队尾。最后,i干掉队尾的位置就落在lp[队尾]和rp[队尾]之间,二分一下即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=500010;
int n,h,t;
int lp[maxn],rp[maxn],v[maxn],p[maxn],q[maxn];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
double solve(int a,int b)
{
	return v[a]-v[b]+sqrt(abs(b-a));
}
int main()
{
	n=rd();
	int i,l,r,mid;
	for(i=1;i<=n;i++)	v[i]=rd();
	for(h=1,t=0,i=1;i<=n;i++)
	{
		while(h<=t&&rp[q[h]]<i)	h++;
		if(h<=t)	lp[q[h]]=i,p[i]=max(p[i],(int)ceil(solve(q[h],i)));
		if(h>t||solve(i,n)>solve(q[t],n))
		{
			rp[i]=n;
			while(h<=t&&solve(i,lp[q[t]])>=solve(q[t],lp[q[t]]))	t--;
			if(h<=t)
			{
				l=lp[q[t]],r=rp[q[t]]+1;
				while(l<r)
				{
					mid=l+r>>1;
					if(solve(i,mid)<solve(q[t],mid))	l=mid+1;
					else	r=mid;
				}
				rp[q[t]]=l-1,lp[i]=l;
			}
			else	lp[i]=i+1;
			q[++t]=i;
		}
	}
	for(h=1,t=0,i=n;i>=1;i--)
	{
		while(h<=t&&lp[q[h]]>i)	h++;
		if(h<=t)	rp[q[h]]=i,p[i]=max(p[i],(int)ceil(solve(q[h],i)));
		if(h>t||solve(i,1)>solve(q[t],1))
		{
			lp[i]=1;
			while(h<=t&&solve(i,rp[q[t]])>=solve(q[t],rp[q[t]]))	t--;
			if(h<=t)
			{
				l=lp[q[t]],r=rp[q[t]];
				while(l<r)
				{
					mid=l+r>>1;
					if(solve(i,mid)<solve(q[t],mid))	r=mid;
					else	l=mid+1;
				}
				lp[q[t]]=r,rp[i]=r-1;
			}
			else	rp[i]=i-1;
			q[++t]=i;
		}
	}
	for(i=1;i<=n;i++)	printf("%d\n",p[i]);
	return 0;
}
posted @ 2017-07-30 09:06  CQzhangyu  阅读(737)  评论(0编辑  收藏  举报