题意:
给定一串数字,里面存在多少个区间[l, r] 使得里面的最大值与最小值之差小于k。
思路:
用RMQ预处理出所有区间的最大值与最小值之差。之后枚举左端点L, 二分处理差值小于k的最左边端点R,把所有
的R-L+1加上就是答案。
/***********************************************
* Author: fisty
* Created Time: 2015-08-20 22:09:44
* File Name : hdu5289.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, k<<1
#define rson m+1, r, k<<1|1
#define MAX_N 100100
int t;
int n, k;
int a[MAX_N];
int mi[MAX_N][20], ma[MAX_N][20];
void RMQ()
{
for (int i = 0; i < n; ++i)
mi[i][0] = ma[i][0] = a[i];
for (int j = 1; (1<<j) <= n; ++j)
for (int i = 0; i+(1<<j)-1 < n; ++i)
{
mi[i][j] = min(mi[i][j-1], mi[i+(1<<(j-1))][j-1]);
ma[i][j] = max(ma[i][j-1], ma[i+(1<<(j-1))][j-1]);
}
}
int query(int lt, int rt)
{
int k = 0;
while ((1<<(k+1)) <= rt-lt+1)
k++;
return max(ma[lt][k], ma[rt-(1<<k)+1][k]) - min(mi[lt][k], mi[rt-(1<<k)+1][k]);
}
int Binary_Search(int x){
int l = x, r = n-1;
while(r - l > 1){
int mid = (l + r) / 2;
if(query(x, mid) < k) l = mid;
else r = mid;
}
if(query(x, r) < k)
return r;
return l;
}
void solve(){
LL ans = 0;
int t;
for(int i = 0;i < n; i++){
t = Binary_Search(i);
ans += t - i + 1;
}
printf("%lld\n", ans);
}
int main() {
//freopen("in.cpp", "r", stdin);
//cin.tie(0);
//ios::sync_with_stdio(false);
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &k);
for(int i = 0;i < n; i++){
scanf("%d", &a[i]);
}
RMQ();
solve();
}
return 0;
}
2.线段树:
首先,以a[n]起始的区间肯定是[n, n]。
然后以a[n-1]起始的区间最长是[n-1, n],然后考虑需不需要把区间的右值减小,也就是考虑a[n]和a[n-1]的差值是否小于k。假设最终的区间为[n-1, d(n-1)]。
于是对于以a[n-2]起始的区间,自然最长是[n-2, d(n-1)],然后考虑需不需要把区间的右值减小,也就是考虑这个区间内是否存在某个值与a[n-2]的差值大于等于k。
以此类推,以a[i]起始的区间应为[i, min(d(i+1), p)],其中p是i右侧最后一个满足与a[i]差值小于k的数的脚标。
采用线段树记录区间的最大值和最小值,就能查询出任意[i, n]区间里第一个满足与a[i]差值大于等于k的值的位置x,然后x-1即为最后一个满足与a[i]差值小于k的数的脚标。
/***********************************************
* Author: fisty
* Created Time: 2015-08-21 20:26:03
* File Name : hdu5289 (2).cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
//线段树版
//采用线段树记录区间的最大值和最小值,就能查询出任意[i, n]区间里第一个满足与
//Ai差值大于等于k的值的位置x,然后x-1即为最后一个满足与Ai差值小于k的数的脚标。
int n, k;
const int MAX_N = 110000;
int _max[MAX_N << 2];
int _min[MAX_N << 2];
int p = -1;
int a[MAX_N];
struct Tree{
void pushup(int rt){
_max[rt] = max(_max[rt<<1], _max[rt<<1|1]);
_min[rt] = min(_min[rt<<1], _min[rt<<1|1]);
}
void build(int l, int r, int rt){
_max[rt] = _min[rt] = 0;
if(l == r){
_min[rt] = _max[rt] = a[l];
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void query(int a, int b, int v){
query(a, b, 1, n, 1, v);
}
void query(int a, int b, int l, int r, int rt, int v){
if(l == r){
if(abs(_min[rt] - v) >= k){
if(p == -1 || p > l){
p = l;
}
}
return;
}
int m = (l + r) >> 1;
if(a <= m){
if(abs(_min[rt<<1] - v) >= k || abs(_max[rt<<1] - v) >= k){
query(a, b, lson, v);
}
}
if(p == -1 && b > m){
if(abs(_min[rt<<1|1] - v) >= k || abs(_max[rt<<1|1] - v) >= k){
query(a, b, rson, v);
}
}
}
}segtree;
int t;
void solve(){
LL ans = 1;
int d[MAX_N];
d[n] = n;
for(int i = n-1; i >= 1; i--){
p = -1;
segtree.query(i, n, a[i]);
if(p == -1){
p = n;
}else{
p--;
}
d[i] = min(d[i+1], p);
ans += d[i] - i + 1;
}
printf("%lld\n", ans);
}
int main() {
//freopen("in.cpp", "r", stdin);
//cin.tie(0);
//ios::sync_with_stdio(false);
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &k);
for(int i = 1;i <= n; i++){
scanf("%d", &a[i]);
}
segtree.build(1, n, 1);
solve();
}
return 0;
}