#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const int M = 110000;
int n,m,a[M],Min[M][30],Max[M][30]; // Min[i][j] 以i开头 ~ i+2^j -1 结尾中的最小值
void RMQ()
{
for(int i=1;i<=n;i++)
{
Min[i][0]=a[i];
Max[i][0]=a[i]; // i开头长度为2^0 为本身
}
//最大值时 dp[i][j]= max(dp[i][j-1],dp[i+2^(j-1)][j-1])
for(int j=1;(1<<j)<=n;j++) //2^j不大于n
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
}
}
}
int Query(int l,int r)
{
int k;
//k=log((double)(r-l+1))/log(2.0); // 使 2^k<= r-l+1 <= 2^(k+1)
k=log2(r-l+1);
int x=min(Min[l][k],Min[r-(1<<k)+1][k]);
int y=max(Max[l][k],Max[r-(1<<k)+1][k]);
if(y-x<m) return 1;
else return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
RMQ();
long long ans=0;
for(int i=1;i<=n;i++) //枚举左端点 (i,p)成立 则(i,q) (q<p)肯定成立 所以找到满足的最远右端点p 则以i开头的合法个数有 p-i+1
{ // (i,p) 不成立 则(i,q) (q>p)肯定不成立 最值之差只会越来越大
int pos;
int l=i,r=n;
while(l<=r) // 二分找到右端点
{
int mid=(l+r)/2;
if(Query(i,mid)) //
{
l=mid+1;
pos=mid;
}
else
{
r=mid-1;
}
}
ans+=(pos-i+1);
}
cout<<ans<<endl;
}
return 0;
}
hdu 5289 RMQ运用
最新推荐文章于 2017-07-18 22:58:43 发布