【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[队尾]之间,二分一下即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#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 @   CQzhangyu  阅读(738)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示