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