利普希茨【NOIP2017模拟8.7A组】

来源:互联网 发布:煤炭行业数据 编辑:程序博客网 时间:2024/06/04 08:21

题目

这里写图片描述

Input

输入文件名为lipschitz.in。
第一行一个整数n。
接下来一行n个整数,描述序列A。
第三行一个数q 。
接下来q行,每行三个整数。其中第一个整数type表示操作的类型。 type=0对应修改操作, type=1对应查询操作。

Output

输出文件名为lipschitz.out。
对于每个查询,给出f(A[l..r]) 。

Sample Input

6
90 50 78 0 96 20
6
0 1 35
1 1 4
0 1 67
0 4 11
0 3 96
1 3 5

Sample Output

78
85

Data Constraint

对于30%的数据,n,q<=500
对于60%的数据,n,q<=5000
对于100%的数据,n,q<=100000,0<=ai,val<=10^9


思路

比赛时是猜想应该只和相邻的有关系,不过没时间去证了。


解法

首先能证明出最优答案一定是选择两个相邻的数。
假设三个数a < b < c,a与b间有x个数,b与c之间有y个数。我们令选a,c比选a,b与b,c更优。
选a,b代价为Vab=bax+1,选b,c代价为Vbc=cby+1
选a,c代价为Vac=cax+y+2
Vab<Vac,Vbc<Vac
(ba)(x+y+2)<(ca)(x+1),(cb)(x+y+2)<(ca)(y+1)
两个式子一加,发现左边=右边,这就意味着两个式子至少有一项不符合。

所以只需要用一个数组存下相邻两个数的差的绝对值,每次修改是修改两个,维护最大值,用上一些数据结构即可。
时间O(n log n).


代码

#include<cstdio>#include<algorithm>#include<cstring>#include<cstdlib>#include<cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;const int maxn=1e5+5;int tree[maxn*4],a[maxn],n,q,ans,b[maxn];void maketree(int p,int l,int r){    if (l==r) tree[p]=b[l];    else {        int mid=(l+r)>>1;        maketree(p<<1,l,mid);        maketree(p<<1|1,mid+1,r);        tree[p]=max(tree[p<<1],tree[p<<1|1]);    }}void change(int p,int l,int r,int pos,int val){    if (l==r) tree[p]=val;    else {        int mid=(l+r)>>1;        if (pos<=mid) change(p<<1,l,mid,pos,val);        else change(p<<1|1,mid+1,r,pos,val);        tree[p]=max(tree[p<<1],tree[p<<1|1]);    }}int getans(int p,int l,int r,int a,int b){    if (l==a&&r==b) ans=max(ans,tree[p]);    else {        int mid=(l+r)>>1;        if (b<=mid) getans(p<<1,l,mid,a,b);        else if (a>mid) getans(p<<1|1,mid+1,r,a,b);        else {            getans(p<<1,l,mid,a,mid);            getans(p<<1|1,mid+1,r,mid+1,b);        }    }}int main(){    freopen("lipschitz.in","r",stdin);    freopen("lipschitz.out","w",stdout);    scanf("%d",&n);    fo(i,1,n) scanf("%d",&a[i]),b[i-1]=abs(a[i]-a[i-1]);    maketree(1,1,n-1);    scanf("%d",&q);     fo(i,1,q){        int t,x,y;        scanf("%d%d%d",&t,&x,&y);        if (!t) {            a[x]=y;            b[x-1]=abs(a[x]-a[x-1]);            b[x]=abs(a[x]-a[x+1]);            change(1,1,n-1,x-1,b[x-1]);            change(1,1,n-1,x,b[x]);        }         else {            ans=0;            if (x!=y) getans(1,1,n-1,x,y-1);            printf("%d\n",ans);        }    }}

这里写图片描述

原创粉丝点击