周赛 摆蔬菜1 题解(线段树+二分or单调队列)

题目链接

题目思路

显然可以线段树+二分直接来,也可以单调队列,单调队列的代码要仔细研究

主要为了研究单调队列的操作

线段树代码

#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;
}
发布了68 篇原创文章 · 获赞 2 · 访问量 2252

猜你喜欢

转载自blog.csdn.net/m0_46209312/article/details/105184447
今日推荐