题意:
给你n个人和一个k
问你把这n个人分成多少个连续的子区间,要求区间每个数两两相差绝对值小于k
思路:
我们仅仅只需要对于当前位置,最左边那个和它绝对值相差大于等于k 的位置在哪
假设对于i这个位置,最左边的位置是tep,不存在的话tep=0
那么当且位置的贡献就是 sum[i]=min(i-max(x1,x2),sum[i-1]+1);
那么对于这个位置怎么求的话,我是使用了两个单调队列
同时维护两个单调队列
一个最大一个最小。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
using namespace std;
#define N 222222
#define ll __int64
int q1[N],q2[N],v[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) scanf("%d",&v[i]);
int top1,top2,ed1,ed2,x1,x2;
top1=top2=ed1=ed2=x1=x2=0;
ll ans=0,sum=0;
for(int i=1; i<=n; i++)
{
while(top1<ed1 && v[q1[ed1-1]]<=v[i] ) ed1--; //Max
q1[ed1++]=i;
while(top2<ed2 && v[q2[ed2-1]]>=v[i] ) ed2--; //Min
q2[ed2++]=i;
while(v[q1[top1]]-v[q2[top2]]>=k)
{
if(q1[top1]<q2[top2]) x1=q1[top1++];
else x2=q2[top2++];
}
sum=min(sum+1,(ll)i-max(x1,x2));
ans+=sum;
}
printf("%I64d\n",ans);
}
return 0;
}