【POI2011】Lightning Conductor_【JSOI2016】灯塔(决策单调性优化dp)

首先进行变形:

\[\begin{aligned} a_j&\leq a_i+p-\sqrt{|i-j|}\\ p&\geq \max_{j=1}^n\left(a_j+\sqrt{|i-j|}\right)-a_i \end{aligned} \]

\(|i-j|\) 拆为 \(\max(i-j,j-i)\)

\[p\geq \max\left(\max_j\left(a_j+\sqrt{i-j}\right),\max_j\left(a_j+\sqrt{j-i}\right)\right)-a_i \]

两部分做法是一样的,这里只说第一部分。

如果设函数 \(f_j(x)=\sqrt{x-j}+a_j\),那么我们就是要求这些函数在每个 \(x=i\) 的最大值。

盗一张 Flash_Hu 巨佬的图:

显然一个函数至多会对应一个区间的最大值,而且对应着最大值的函数肯定越往后编号越大(因为导致最大值的函数改变的原因只可能是加入了一个编号更大的函数)。

那么我们从编号小到编号大加入这些函数并且用栈维护对应着最大值的函数。

新加入一个函数时,如果它能超过当前栈顶的函数,那么就求交。注意求得的交点也可能在栈顶的函数所对应的最大值区间的左边,这时需要弹出栈顶,然后和新的栈顶再进行比较。比如下图这种情况:

在这里插入图片描述

我们先加入了函数 \(f\)\(h\),再加入函数 \(g\) 时,发现 \(g\) 与栈顶 \(h\) 的交点在 \(h\) 对应的最大值区域的左边,那么就需要弹出 \(h\),重新让 \(f\)\(g\) 比较。

代码如下:

#include<bits/stdc++.h>

#define N 500010

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

struct data
{
	int p,l,r;
	data(){};
	data(int a,int b,int c){p=a,l=b,r=c;}
}q[N];

int n,a[N];
int maxid[N];
int tail;

double gety(int i,int x)
{
	return sqrt(abs(x-i))+1.0*a[i];
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	q[++tail]=data(1,1,n);
	for(int i=2;i<=n;i++)
	{
		if(a[i]<=a[q[tail].p]) continue;
		if(gety(i,n)>gety(q[tail].p,n))
		{
			int l=i,r=n,ans=-1;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(gety(i,mid)>gety(q[tail].p,mid)) ans=mid,r=mid-1;
				else l=mid+1;
			}
			if(ans<=q[tail].l)
			{
				tail--;
				i--;
				continue;
			}
			q[tail].r=ans-1;
			q[++tail]=data(i,ans,n);
		}
	}
	for(int i=n;i>=1;i--)
	{
		if(i<q[tail].l) tail--;
		maxid[i]=q[tail].p;
	}
	q[++tail]=data(n,1,n);
	for(int i=n-1;i>=1;i--)
	{
		if(a[i]<=a[q[tail].p]) continue;
		if(gety(i,1)>gety(q[tail].p,1))
		{
			int l=1,r=i,ans=-1;
			while(l<=r)
			{
				int mid=(l+r)>>1;
				if(gety(i,mid)>gety(q[tail].p,mid)) ans=mid,l=mid+1;
				else r=mid-1;
			}
			if(ans>=q[tail].r)
			{
				tail--;
				i++;
				continue;
			}
			q[tail].l=ans+1;
			q[++tail]=data(i,1,ans);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(i>q[tail].r) tail--;
		double x=max(gety(q[tail].p,i),gety(maxid[i],i));
		printf("%d\n",max(0,(int)ceil(x-a[i])));
	}
	return 0;
}
posted @ 2022-10-29 11:23  ez_lcw  阅读(21)  评论(0编辑  收藏  举报