题目描述:
题目给你一个长度为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; }