HDU5289 单调队列 or 线段树

1.单调队列

类似尺取法的思想,动态维护区间的最大最小值,设出头,尾指针,像尺取法一样移动,

遇到不合法区间时尾指针停止移动,头指针向右移动,并计数

#include <bits/stdc++.h>
using namespace std ;
typedef long long LL;
deque <LL> Max , Min ;
LL T , n , k;
LL s[100010] ;
int main()
{
    scanf("%d", &T) ;
    while( T-- )
    {
        LL sum = 0;
        cin >> n >> k;
        for(int i = 1 ; i <= n ; i++) cin >> s[i];
        Max.clear();Min.clear();
        LL i , j;

        for(i = 1 , j = 1; j <= n ; j++)
        /*
            j是右边界,i是左边界,每次在末尾插入一个数字,然后判断
            区间的可行性。如果:
            可行:j继续向右拓展
            不可行:i开始向右拓展,同时计数,一直到区间长度变为0,或者ji组成的区间可行
        */
        {
            while( !Max.empty() && Max.back() < s[j] ) Max.pop_back() ;
            Max.push_back(s[j]);
            while( !Min.empty() && Min.back() > s[j] ) Min.pop_back() ;
            Min.push_back(s[j]) ;
            /*
                单调队列Max保证在我们面对区间[i-j]的时候,Max.front是区间的最大值
                Min同理
            */
            while(!Max.empty() && (Max.front() - Min.front() >= k))
            {
                sum += (j-i);
                if( Max.front() == s[i] ) Max.pop_front() ; //动态更新Max
                if( Min.front() == s[i] ) Min.pop_front() ;//...
                i++;
            }
        }
        while(i <= n){sum+=(j-i);i++;}
        cout << sum << endl;
    }
    return 0 ;
}

2.线段树

只是把维护最大最小值的地方改成用线段树维护就可以了,复杂度变成nlogn

猜你喜欢

转载自blog.csdn.net/zhaiqiming2010/article/details/80280868