[2020牛客算法竞赛入门课第九节习题] 求最大值 贪心+线段树

题目链接:求最大值

题意

给你一个长度为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}} a2a1,a3a2,....,anan1= b 1 , b 2 , . . . . . , b n − 1 {b_1,b_2,.....,b_{n-1}} b1,b2,.....,bn1
我们只需维护这个差分序列的最大值即可。

注意在修改 a i {a_i} ai时会对两个差分值产生影响。
如果我们修改 a i 为 v {a_i为v} aiv时, 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+1ai,di1=aiai1,那么 d i + = a i − v , d i − 1 + = v − a i {d_i+=a_i-v,d_{i-1}+=v-a_i} di+=aivdi1+=vai

注意两边的数对差分数列值只有一次影响,例如修改 a n {a_n} an,只对 d n − 1 {d_{n-1}} dn1有影响,所以无需对不存在的 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));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44235989/article/details/108099512