题目链接
题目思路
显然可以线段树+二分直接来,也可以单调队列,单调队列的代码要仔细研究
主要为了研究单调队列的操作
线段树代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
ll sum[maxn],ans;
int n,m,a[maxn],tree1[maxn<<2],tree2[maxn<<2];
void build1(ll p,ll l,ll r){//tree1代表最小值
if(l==r){
tree1[p]=a[l];
return ;
}
ll mid=(l+r)>>1;
build1(p<<1,l,mid);
build1(p<<1|1,mid+1,r);
tree1[p]=min(tree1[p<<1],tree1[p<<1|1]);
return ;
}
void build2(ll p,ll l,ll r){//tree2代表最大值
if(l==r){
tree2[p]=a[l];
return ;
}
ll mid=(l+r)>>1;
build2(p<<1,l,mid);
build2(p<<1|1,mid+1,r);
tree2[p]=max(tree2[p<<1],tree2[p<<1|1]);
return ;
}
int query1(int node,int L,int R,int l,int r){
if(l<=L&&r>=R){
return tree1[node];
}
int mid=(L+R)/2,ans=inf;
if(mid>=l) ans=min(ans,query1(node<<1,L,mid,l,r));
if(mid<r) ans=min(ans,query1(node<<1|1,mid+1,R,l,r));
return ans;
}
int query2(int node,int L,int R,int l,int r){
if(l<=L&&r>=R){
return tree2[node];
}
int mid=(L+R)/2,ans=-inf;
if(mid>=l) ans=max(ans,query2(node<<1,L,mid,l,r));
if(mid<r) ans=max(ans,query2(node<<1|1,mid+1,R,l,r));
return ans;
}
bool check(int l,int r){
if(query2(1,1,n,l,r)-query1(1,1,n,l,r)<=m)
return 1;
return 0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];//前缀和
}
build1(1,1,n);//建树最小值
build2(1,1,n);//建树最大值
for(int i=1;i<=n;i++){//二分
int l=i,r=n;
while(l<=r){
int mid=(l+r)/2;
if(check(i,mid)){
ans=max(ans,sum[mid]-sum[i-1]);
l=mid+1;
}else{
r=mid-1;
}
}
}
printf("%lld",ans);
return 0;
}
单调队列
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,m,a[maxn],deqmin[maxn],deqmax[maxn],left=1;
ll ans,sum[maxn];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];//前缀和
}
int lmin=1,rmin=0,lmax=1,rmax=0; //左右边界
for(int i=1;i<=n;i++){
while(lmin<=rmin&&a[deqmin[rmin]]>=a[i]){//单调上升的队列
rmin--;
}
while(lmax<=rmax&&a[deqmax[rmax]]<=a[i]){//单调下降的队列
rmax--;
}
deqmin[++rmin]=deqmax[++rmax]=i;
while(lmin<=rmin&&lmax<=rmax&&a[deqmax[lmax]]-a[deqmin[lmin]]>m){
if(deqmin[lmin]<=deqmax[lmax]){
//left=min(deqmin[++lmin],deqmax[lmax]);注意不是这个,因为只是减少了一个数组 ,而中间有很多元素
left=deqmin[lmin]+1,lmin++;
}else{
//left=min(deqmin[lmin],deqmax[++lmax]);
left=deqmax[lmax]+1,lmax++;
}
}
if(lmin<=rmin&&lmax<=rmax&&a[deqmax[lmax]]-a[deqmin[lmin]]<=m){
ans=max(ans,sum[i]-sum[left-1]);
}
}
printf("%lld",ans);
return 0;
}