HDU3530 Subsequence(单调队列)

题意是说给出一个序列,现在要求出这个序列的一个最长子区间,要求子区间的最大值与最小值的差在[m, k]范围内,求区间长度

做法是维护两个队列,一个维护到当前位置的最大值,一个维护最小值,然后计算当前节点i作为右端点的最常区间长度,那么扫描两个队列,维持单调性。

然后比较两个队列头的差值,

1.如果差值满足条件,那么记录答案;

2.如果差值小于m,那么此时没有答案,说明没有以i作为右端点的区间满足条件(表示前i个数的最大值减去前i个数的最小值的差<m,那么不论如何调整起点,都不可能有解)

3.如果差值大于k,说明此时区间的最大值与最小值的差过大,那我们可以通过缩小最大值(最大值(递减)队列向右移动)或者增大最小值(最小值(递增)队列向右移动)的方法使得差值变小,那到底是移动哪一个指针取决于此时队首的这两个值谁的编号要小(保证区间是合法的)。

另外有一点要注意的细节是,上述的第三种情况,在移动队首的指针时,如果最后被删除的元素所指向的下标p,此时队首的元素指向的下标是q, 此时合法区间为[p +1, i]而不是[q, i]

 1 //#pragma comment(linker, "/STACK:1677721600")
 2 #include <map>
 3 #include <set>
 4 #include <stack>
 5 #include <queue>
 6 #include <cmath>
 7 #include <ctime>
 8 #include <vector>
 9 #include <cstdio>
10 #include <cctype>
11 #include <cstring>
12 #include <cstdlib>
13 #include <iostream>
14 #include <algorithm>
15 using namespace std;
16 #define INF 0x3f3f3f3f
17 #define inf (-((LL)1<<40))
18 #define lson k<<1, L, (L + R)>>1
19 #define rson k<<1|1,  ((L + R)>>1) + 1, R
20 #define mem0(a) memset(a,0,sizeof(a))
21 #define mem1(a) memset(a,-1,sizeof(a))
22 #define mem(a, b) memset(a, b, sizeof(a))
23 #define FIN freopen("in.txt", "r", stdin)
24 #define FOUT freopen("out.txt", "w", stdout)
25 #define rep(i, a, b) for(int i = a; i <= b; i ++)
26 #define dec(i, a, b) for(int i = a; i >= b; i --)
27
28 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
29 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
32
33 //typedef __int64 LL;
34 typedef long long LL;
35 const int MAXN = 100000 + 100;
36 const int MAXM = 110000;
37 const double eps = 1e-8;
38 LL MOD = 1000000007;
39
40 int a[MAXN], L, H, n;
41 int q1[MAXN], q2[MAXN];
42
43 int find_ans() {
44     int f1, f2, t1, t2, l1 = -1, l2 = -1, ans = 0;
45     f1 = f2 = t1 = t2 = 0;
46     rep (i, 0, n - 1) {
47         while(f1 < t1 && a[q1[t1 - 1]] <= a[i]) t1 --;//维护最大值队列(递减)
48         q1[t1++] = i;
49         while(f2 < t2 && a[q2[t2 - 1]] >= a[i]) t2 --;//维护最小值队列(递增)
50         q2[t2++] = i;
51         while(a[q1[f1]] - a[q2[f2]] > H) {//差值过大
52             q1[f1] < q2[f2] ? l1 = q1[f1 ++] : l2 = q2[f2 ++];
53         }
54         if(a[q1[f1]] - a[q2[f2]] >= L) {//差值满足条件
55             ans = max(ans, i - max(l1, l2));
56         }
57     }
58     return ans;
59 }
60
61 int main()
62 {
63     while(~scanf("%d %d %d", &n, &L, &H)) {
64         rep (i, 0, n - 1) scanf("%d", a + i);
65         printf("%d\n", find_ans());
66     }
67     return 0;
68 }
时间: 2024-11-06 09:14:21

HDU3530 Subsequence(单调队列)的相关文章

hdu3530 Subsequence 单调队列

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

hdu3530 双单调队列的维护

单调队列有部分堆的功能,但其只能维护给定区间中比v大的值或者比v小的值,且其一般存储元素的下标. 思路:两个单调队列维护最大值与最小值的下标,如果区间的最大值最小值之差大于给定范围,则选择队首靠左的删去,并记录删去元素的下标,然后维护最大区间长度即可 注意有两个范围,第二个范围不能忽略 /* 单调队列存储区间最大值,最小值 如果Max-Min>k,呢么左端点靠前的删掉队头元素,删掉时记录下标 */ #include<iostream> #include<cstring> #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):可以用来维护区间的单调性,用来解决最大或最小的问题

[hdu3530]单调队列

题意:求满足最大元素与最小元素之差在一定范围的连续区间的最大长度.单调队列经典应用. 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <cstring> 6 #include <map> 7 #include <queue> 8 #include <deque> 9

hdu 3415 单调队列

Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5690    Accepted Submission(s): 2059 Problem Description Given a circle sequence A[1],A[2],A[3]......A[n]. Circle s

hdu 3530 (单调队列)

Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4441    Accepted Submission(s): 1457 Problem Description There is a sequence of integers. Your task is to find the longest subsequenc

POJ 3017 单调队列dp

Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 Description Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subseque

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

Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7034    Accepted Submission(s): 2589 Problem Description Given a circle sequence A[1],A[2],A[3]......A[n]. Circle se

HDU 3530 单调队列

Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3995    Accepted Submission(s): 1308 Problem Description There is a sequence of integers. Your task is to find the longest subsequenc