蓝桥杯 5.龙骑士军团【算法赛】题型:查询区间最值 知识点:线段树/st表 难度:难

53 阅读1分钟

5.龙骑士军团【算法赛】 - 蓝桥云课 (lanqiao.cn)

暴力

这道题要求我们求最大区间和 一共有a b c d四个数

可以枚举出来4段区间: [a,c] [a,d] ,[b,c],[b,d]

每次遍历这些区间进行求和,一共q次,那就是O(n*q),n,q都是2e5,会超时的.

正解

首先利用前缀和O(1)复杂度求前缀和.然后再用st表/线段树 log的复杂度查区间和最大

因为本题不涉及修改,所有可以用st表.

具体做法如下:

image.png

记得开Long long ,每个a[i]最大1e9

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
const int N=2e5+10;
int a[N],sum[N];
int maxn[N][26],minn[N][26];
int getMAX(int l,int r)
{
	int k=log2(r-l+1);
	return max(maxn[l][k],maxn[r-(1<<k)+1][k]);
}
int getMIN(int l,int r)
{
	int k=log2(r-l+1);
	return min(minn[l][k],minn[r-(1<<k)+1][k]);
}
signed main()
{
  cin.tie(nullptr)->sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
			for(int i=1;i<=n;i++)
		{
		    //因为要计算到前缀和最大最小区间和 
			maxn[i][0]=sum[i];
			minn[i][0]=sum[i];
		}
	//这个21取决于题目的数据,数据越大,21就要往上提 
	for(int j=1;j<=21;j++)
	{
		for(int i=0;i+(1<<j)-1<=n;i++)
		{
			maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);
			minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]); 
		}
    }   
    
    while(m--)
    {
    	int a,b,c,d;cin>>a>>b>>c>>d;
    	cout<<getMAX(c,d)-getMIN(a-1,b-1)<<endl;
	}
	return 0;
}

image.png