hdu3530 双单调队列的维护

单调队列有部分堆的功能,但其只能维护给定区间中比v大的值或者比v小的值,且其一般存储元素的下标。

思路:两个单调队列维护最大值与最小值的下标,如果区间的最大值最小值之差大于给定范围,则选择队首靠左的删去,并记录删去元素的下标,然后维护最大区间长度即可

注意有两个范围,第二个范围不能忽略

/*
单调队列存储区间最大值,最小值
如果Max-Min>k,呢么左端点靠前的删掉队头元素,删掉时记录下标
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100005

using namespace std;

int n,m,k,a[maxn],q_max[maxn],q_min[maxn];

int main(){
    while(scanf("%d%d%d",&n,&m,&k)==3){
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int l_min=0,r_min=0,l_max=0,r_max=0;
        int last1=0,last2=0,ans=0;

        for(int i=1;i<=n;i++){
            //队尾插入元素
            while(l_min<r_min&&a[q_min[r_min-1]]>=a[i]) r_min--;
            while(l_max<r_max&&a[q_max[r_max-1]]<=a[i]) r_max--;
            q_min[r_min++]=q_max[r_max++]=i;
            while(a[q_max[l_max]]-a[q_min[l_min]]>k){
                if(q_max[l_max]<q_min[l_min]) last2=q_max[l_max++];
                else last1=q_min[l_min++];
            }
            if(a[q_max[l_max]]-a[q_min[l_min]]>=m)//这个条件还是要判的
            ans=max(ans,i-max(last1,last2));
        }
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zsben991126/p/10140237.html

时间: 2024-10-11 03:53:15

hdu3530 双单调队列的维护的相关文章

hdu3530 Subsequence 单调队列

// hdu3530 Subsequence 单调队列 // 题目大意:找到一个最大的子串,使得子串区间内最大值和最小值的差 // 在low和up范围内,串的规模10w. // 解题思路: // 单调队列,单调队列可以保留i位置之前的最大值和最小值的下标,有了这些 // 则,每次我们比较两个队列的队头,看差值是否大于up,(因为它是到i位置最大 // 的差值,其他值不可能比i还要大.) // 如果大于,则将两个对头靠前的那个丢掉,即出队,再比较对头,并且记录下 // 出队的位置下标,(因为此时出

单调队列总结

单调队列 就是保持队列中的元素始终保持单调性,这个数据结构就是单调队列 它的作用就是维护最值.求第一个比i小(大)的数的下标等等 还有个单调栈来着,不过我们可以用一个双端队列就足够了 如果要维护最大值,就用单调递减队列,反之,用递增队列 1.hdu3530 Subsequence 单调队列入门题 这题求的是最大值减去最小值不小于m不大于k的最长长度 这题用单调队列维护最大值和最小值即可 #include<iostream> using namespace std; #define MAX 10

单调队列————[USACO09MAR]向右看齐Look Up

先了解一下单调队列: 很明显的具有单调性 分为单调递增和单调递减两种,简单点讲就是维护队头为最大值或者为最小值 (建议采用双向队列  比较好写) 具体步骤:(这个是单调递减) 如果队列非空且当前值比队尾元素大,不断删除比该值小的元素,否则直接队尾入队 while(!que.empty()&&ma[i]>que.back()) {     que.pop_back(); } que.push_back(i); 单调队列的作用:: 1):可以用来维护区间的单调性,用来解决最大或最小的问题

HDU 3706 Second My Problem First (单调队列)

题意:求给定的一个序列中最长子序列,该子序列的最大值和最小值介于m和k之间. 析:用两个单调队列来维护一个最小值,一个最大值,然后每次更新即可. 代码如下; #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <i

UVA-1619 Feel Good (单调队列)

题目大意:给一个非负整数序列,求出一个使得区间和乘以区间最小值最大的区间. 题目分析:单调队列.维护两个数组,l[i]表示以a[i]为最小值的左半区间的最左边端点,r[i]表示以a[i]为最小值的右半区间的最右边端点,l[i]和r[i]合起来便是以a[i]为最小值的整个区间.枚举一遍 i 即可. 注意:UVA上的这道题有个大大的坑,明明说可以输出任意一个区间(多个解时),实际上是骗人的!!! 代码如下: # include<iostream> # include<cstdio> #

UVA Live Achrive 4327 Parade (单调队列,dp)

容易想到dp[i][j]表示在第i行j个路口的开始走最大高兴值. 每次可以向左走,或者向右边走,然后向北走.(或者直接往北) 向左走到,状态转移为dp[i][j] = dp[i][k] + happy[i][k][j](为了方便处理,i从1开始编号,0行dp值存0) 处理出前缀和,happy[i][k][j]表示为sum[i][j] - sum[i][k] 向左走应该取max(dp[i][k]-sum[i][k]) k应该满足time[i][k][j] <= k 随着j的变化k的范围是一个滑动窗

51nod 1821 最优集合(思维+单调队列)

题意:一个集合S的优美值定义为:最大的x,满足对于任意i∈[1,x],都存在一个S的子集S',使得S'中元素之和为i. 给定n个集合,对于每一次询问,指定一个集合S1和一个集合S2,以及一个数k,要求选择一个S2的子集S3(|S3|<=k),使得S1∪S3的优美值最大. (集合元素可以重复) 我们首先考虑对于集合S1,能否求出它的最大优美值. 首先排序一遍,对于前i个元素,如果它的最大优美值为v,那么当S1[i+1]>v+1时,前i+1个元素的最大优美值依然为v,否则为v+S1[i+1].此处

POJ 2823 Sliding Window(单调队列)

[题目链接] http://poj.org/problem?id=2823 [题目大意] 给出一个数列,问每k个数总最小值和最大值分别是多少 [题解] 单调队列顺序维护需求,时间节点超过k的点就出队 我们维护两次单调队列,用xor的小trick可以降低码量. [代码] #include <cstdio> #include <algorithm> using namespace std; const int MAX_N=1000010; int n,k; int a[MAX_N],b

hdu 3415 Max Sum of Max-K-sub-sequence(单调队列)

题目链接:hdu 3415 Max Sum of Max-K-sub-sequence 题意: 给你一串形成环的数,让你找一段长度不大于k的子段使得和最大. 题解: 我们先把头和尾拼起来,令前i个数的和为sum[i]. 然后问题变成了求一个max{sum[i]-sum[j]}(i-k<j<i) 意思就是对于每一个sum[i],我们只需要找一个满足条件的最小的sum[j],然后我们就可以用一个单调队列来维护. 1 #include<bits/stdc++.h> 2 #define F