Jzoj5236 利普希茨

来源:互联网 发布:网上教育软件 编辑:程序博客网 时间:2024/06/07 03:12

对于一个整数序列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:函数

"

用归纳法,若(长度为2⋯n的序列的答案)都由长度为2的子序列产生,我们将要证明:长度为n+1的序列答案也由长度为2的子序列产生

设它是a1⋯n+1,若答案为它本身而不是其他子序列,那么a1an+1一个是最小一个是最大,不妨设a1<an+1

那么这个序列的Lipshitz常数为an+1−a1n,因为其他长度的子序列的答案都由长度为2的子序列产生,那么对1≤i≤n,都有an+1−a1n>|ai−ai+1|

把这n个不等式加起来,得an+1−a1>|a1−a2|+⋯+|an−an+1|

整理,得a2+|a2−a3|+⋯+|an−1−an|−an<0

移一下绝对值外的,再补上几项,得an−an−1+⋯+a3−a2>|an−an−1|+⋯+|a3−a2|

一个数取绝对值后不会变小,所以这里显然矛盾,原命题得证

因为长度为2的序列的答案显然长度为2,所以对于任意n≥2,长度为n的序列,答案都由长度为2的子序列产生

"

证明完了,我们就可以用差分+线段树乱搞了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])); }}}

原创粉丝点击