值域分块+ST表,也可以决策单调性来做。
发现柿子写成 (p=max{h_j+sqrt{|i-j|}}-h_i) 。
中间的根号不太好处理,但是,我们突然发现,这个是下标之差开根,那么是不是说明其最大是 (sqrt{n}) 的呢?
于是,我们可以考虑预处理每一个 (sqrt{|i-j|}) 的值对应的区间长度,然后枚举每一个值后取这个区间里的区间最大值就行了。
那么询问变成了区间最值,可以使用 ST表 维护。
时间复杂度 (O(nsqrt{n})) ,好像决策单调性做法是 (O(nlogn)/O(n)) 的,具体见 加强版。
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
const int K=17,N=1e5+5;
struct SegMent{int l,r;}s[N];
int st[N][K],h[N],m[N],sq[N],Log[N],n,ans,L;
double k;
inline int sqr(int x){return x*x;}
inline int ask(int l,int r){
l=max(1,l),r=min(r,n);
int len=r-l+1,k=Log[len];
return max(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
read(n);
k=sqrt(n);L=(int)ceil(k);
for(int i=1;i<=n;i++) read(h[i]);
for(int i=1;i<=L;i++){
s[i].l=sqr(i-1)+1,s[i].r=sqr(i);
for(int j=s[i].l;j<=s[i].r;j++) sq[j]=i;
}
Log[1]=0;
for(int i=2;i<=n;i++){
Log[i]=Log[i-1];
if((1<<Log[i]+1)==i) Log[i]++;
}
for(int i=n;i>=1;i--){
st[i][0]=h[i];
for(int j=1;(i+(1<<j)-1)<=n;j++) st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
for(int i=1;i<=n;i++){
ans=0;
for(int j=sq[i-1];j>=1;j--) ans=max(ans,ask(i-s[j].r,i-s[j].l)+j);
for(int j=sq[n-i];j>=1;j--) ans=max(ans,ask(i+s[j].l,i+s[j].r)+j);
write(max(0,ans-h[i])),putchar('
');
}
return 0;
}