HDU3530Subsequence(单调队列)

题意:给n个数和m,k,问你数列中最长的子序列,其中最大值减去最小值大于等于m小于等于k

思路:想着想着想到尺取去了,写了一半实现不了((/ □ \))。维护了两个队列,一个是以当前结束所构成的递减序列的位置,另一个是以当前结束构成的递增序列的位置,然后每次的最大值减去最小值,如果大于k,那么就更新两个中的一个,应该更新位置较小的那个,这样才能使得这个区间的长度最大,然后就这么更新就行了


#include
using namespace std;
const int maxn = 100005;
int a[maxn], Q1[maxn], Q2[maxn];
int main()
{
    int n, m, k;
    while(scanf("%d%d%d", &n, &m, &k) != EOF)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        int s1 = 0, e1 = 0, s2 = 0, e2 = 0, pos = 0, ans = 0;
        for(int i = 1; i <= n; i++)
        {
            while(s1 < e1 && a[Q1[e1-1]] < a[i]) e1--;
            while(s2 < e2 && a[Q2[e2-1]] > a[i]) e2--;
            Q1[e1++] = i;
            Q2[e2++] = i;
            while(s1 < e1 && s2 < e2 && a[Q1[s1]] - a[Q2[s2]] > k)
            {
                if(Q1[s1] < Q2[s2])
                    pos = Q1[s1++];//注意这里是s1++不是++s1
                else
                    pos = Q2[s2++];
            }
            if(a[Q1[s1]] - a[Q2[s2]] >= m)
                ans = max(ans, i - pos);
        }
        printf("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(数据结构)