题目描述:
题目给你一个长度为n的序列,m次询问,每次询问给一个k,寻找有多少个区间【l,r】满足区间内的数组最大值减数组最大值大于k(不等于k)
思路分析:
我们给定一个i,为满足条件的区间左边界。然后往后找右区间边界,我们令j为区间右边界,而我们只需要找出这个区间内满足条件的最小j即可,因为这个j后面的右边界都满足条件。而我们可以用两个单调队列分别来维护这个区间内最小值和最大值。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int m,n,k;
long long ans;
int mm,mx,mi,xi;
int a[100005],maxi[100005],mini[100005];//mini为维护最小值得递增队列,maxi为维护最大值的递减队列
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
while(m--){
ans=0;
cin>>k;
mm=mx=mi=xi=1;//mm,mx,mi,xi分别是maxi队首队尾和mini队首队尾
maxi[1]=mini[1]=1;
int j=1;
for(int i=1;i<=n;i++){
if(maxi[mx]<i)mx++;
if(mini[mm]<i)mm++;
while(j<i||a[maxi[mx]]-a[mini[mm]]<=k){
if(j==n)break;
j++;
while(xi>=mx&&a[maxi[xi]]<a[j])--xi;//维护单调递减队列
while(mi>=mm&&a[mini[mi]]>a[j])--mi;//维护单调递增队列
maxi[++xi]=j;
mini[++mi]=j;
}
if(a[maxi[mx]]-a[mini[mm]]<=k)break;
ans+=n-j+1;//j后面的所有右区间都满足条件
}
cout<<ans<<endl;
}
return 0;
}
京公网安备 11010502036488号