题意:

擅长唱跳rap篮球和music的kunkun也“擅长”排队,每个球员都有已知的能力值,同时kunkun的附加光环使得每个队员对于其后面的人都有附加能力值m,即对于和后面的人比较的时候,他们都在已知能力值上加上m,但是有的队员对这种排名并不满意,所以他们想知道在有附加能力值的情况下,他们与后面队员中比他们能力值大或者相等的队员中最多隔了几个队员。

即求对于,使得  中得到的最大的(>=0)最大为多少,若不存在则输出-1。

题解:单调队列+二分

参照官方题解的,先从排名最后的队员开始从后向前构造一个单调递增队列,序列中存储着能力值索引,当某个数小于等于队尾,那么二分得到最小的大于等于(该数+m)的索引,并且存储下来答案,当二分无结果则存储该位答案为-1

(对于从后向前存储递增队列,那么我们可知如果枚举到某一位时,如果它的值小于队尾,同时此时它的索引比队尾元素的索引更小,那么它没有任何优势,自然无需存储下来)

 

代码如下:

#include<cstdio>
using namespace std;

const int N = 5e5+100;
int a[N], q[N], res[N];
int n, m;

int binary_search(int l, int r, int x){
    while(l < r){
        int mid = (l + r) / 2;
        if(x <= a[q[mid]]) r = mid;
        else l = mid + 1;
    }
    if(x > a[q[l]]) return -1;
    else return l;
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) 
        scanf("%d", &a[i]);
        
    int hh = 0, tt = -1;
    q[++tt] = n, res[n] = -1;
    for(int i = n - 1; i >= 1; i--){
        if(a[i] > a[q[tt]]){
            q[++tt] = i;
            res[i] = -1;
        }
        else{
            int ta = a[i] + m;
            int pos = binary_search(0, tt, ta);
            if(pos == -1) res[i] = -1;
            else res[i] = q[pos] - i - 1;
        }
    }
    
    for(int i = 1; i <= n; i++){
        printf("%d", res[i]);
        if(i != n) printf(" ");
        else puts("");
    }
    return 0;
}