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