对于一个整数序列A,我们定义f(A)=max{floor(|Ai-Aj|/(j-i))},这里i<j
给出一个长度为n的序列A,有q此操作
1.修改一个元素的值
2.询问A的一段区间[l,r]组成的序列的f(A[l..r])
这里有一个很显然的结论,那就是使得f取到最大的i,j一定满足j=i+1
为什么?可以证明一下,以下证明来自jefflyy:函数
"
用归纳法,若(长度为的序列的答案)都由长度为的子序列产生,我们将要证明:长度为的序列答案也由长度为的子序列产生
设它是,若答案为它本身而不是其他子序列,那么和一个是最小一个是最大,不妨设
那么这个序列的Lipshitz常数为,因为其他长度的子序列的答案都由长度为的子序列产生,那么对,都有
把这个不等式加起来,得
整理,得
移一下绝对值外的,再补上几项,得
一个数取绝对值后不会变小,所以这里显然矛盾,原命题得证
因为长度为的序列的答案显然长度为,所以对于任意,长度为的序列,答案都由长度为的子序列产生
"
证明完了,我们就可以用差分+线段树乱搞了233333333
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int w[100010],s[400040],n,m;
inline void update(int l,int r,int x,int p,int k){
if(l==r){ s[x]=k; return ; }
int m=l+r>>1;
if(p<=m) update(l,m,x<<1,p,k);
else update(m+1,r,x<<1|1,p,k);
s[x]=max(s[x<<1],s[x<<1|1]);
}
inline int query(int l,int r,int x,int L,int R){
if(L<=l && r<=R){ return s[x]; }
int m=l+r>>1,ans=0;
if(L<=m) ans=max(ans,query(l,m,x<<1,L,R));
if(m<R) ans=max(ans,query(m+1,r,x<<1|1,L,R));
return ans;
}
int main(){
freopen("lipschitz.in","r",stdin);
freopen("lipschitz.out","w",stdout);
scanf("%d%d",&n,w);
for(int i=1;i<n;++i) scanf("%d",w+i),update(1,n,1,i,abs(w[i]-w[i-1]));
scanf("%d",&m);
for(int a,b,c,i=0;i<m;++i){
scanf("%d%d%d",&a,&b,&c);
if(a) printf("%d\n",query(1,n,1,b,c-1));
else { w[b-1]=c; update(1,n,1,b,abs(w[b]-w[b-1])); if(b>1) update(1,n,1,b-1,abs(w[b-1]-w[b-2])); }
}
}