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表.
具体做法如下:
记得开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;
}