题目链接:求最大值
题意
给你一个长度为n的序列,让你求整个序列中 (a[j]-a[i]) / (j-i) [1<=i<j<=n] 的最大值。其中会有q次操作,每次操作会选择一个位置上的数并将其变为y。每次操作完后输出最大值。
题解
不难看出,我们构建一个笛卡尔积<i,a[i]>,那么(a[j]-a[i]) / (j-i) 就是求一个二维坐标系里两点之间的斜率最大值,其实又很容易想出斜率最大值的两个点一定是连续的。由于这些点的x坐标不会相同,那么(a[j]-a[i]) / (j-i)的最大值就是这n个序列相邻之间差值最大值。
我们可以构建一个差分序列:
a
2
−
a
1
,
a
3
−
a
2
,
.
.
.
.
,
a
n
−
a
n
−
1
{a_2-a_1,a_3-a_2,....,a_n-a_{n-1}}
a2−a1,a3−a2,....,an−an−1=
b
1
,
b
2
,
.
.
.
.
.
,
b
n
−
1
{b_1,b_2,.....,b_{n-1}}
b1,b2,.....,bn−1
我们只需维护这个差分序列的最大值即可。
注意在修改
a
i
{a_i}
ai时会对两个差分值产生影响。
如果我们修改
a
i
为
v
{a_i为v}
ai为v时,
d
i
=
a
i
+
1
−
a
i
,
d
i
−
1
=
a
i
−
a
i
−
1
{d_i=a_{i+1}-a_i,d_{i-1}=a_i-a_{i-1}}
di=ai+1−ai,di−1=ai−ai−1,那么
d
i
+
=
a
i
−
v
,
d
i
−
1
+
=
v
−
a
i
{d_i+=a_i-v,d_{i-1}+=v-a_i}
di+=ai−v,di−1+=v−ai
注意两边的数对差分数列值只有一次影响,例如修改 a n {a_n} an,只对 d n − 1 {d_{n-1}} dn−1有影响,所以无需对不存在的 d n {d_n} dn进行修改。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lowbit(x) x&-x
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const ll inf=3e9;
const int maxn=2e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int gcd(int a,int b) { return b==0 ?a:gcd(b,a%b); }
ll d[maxn],a[maxn];
ll tree[maxn<<2];
void build(int p,int l,int r)
{
if(l==r) { tree[p]=d[l]; return;}
int mid=l+(r-l)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
tree[p]=max(tree[p*2],tree[p*2+1]);
}
void add(int p,int l,int r,int pos,int v)
{
if(l==r) { tree[p]+=v; return ; }
int mid=l+(r-l)/2;
if(pos<=mid) add(p*2,l,mid,pos,v);
if(pos>mid) add(p*2+1, mid+1, r, pos, v);
tree[p]=max(tree[p*2],tree[p*2+1]);
}
ll query_max(int p,int l,int r,int ql,int qr)
{
if(ql<=l && qr>=r) return tree[p];
int mid=l+(r-l)/2;
ll ans=-inf;
if(ql<=mid) ans=max(ans,query_max(p*2, l, mid, ql, qr));
if(qr>mid) ans=max(ans,query_max(p*2+1, mid+1, r, ql, qr));
return ans;
}
int main()
{
int n;
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=2;i<=n;i++) d[i-1]=a[i]-a[i-1];
build(1,1,n-1);
int m; scanf("%d",&m);
while(m--)
{
ll pos,v; scanf("%lld%lld",&pos,&v);
if(pos<n) add(1, 1, n-1, pos, a[pos]-v);
if(pos>1) add(1, 1, n-1, pos-1, v-a[pos]);
a[pos]=v;
printf("%lld.00\n",query_max(1, 1, n-1, 1, n-1));
}
}
}