题目大意

给你长度为的序列,并且有次查询,每次查询给出一个,询问在中有多少个区间的最大值减掉最小值严格大于

Solution

考点:双指针+

考虑到区间不会修改,那么查找区间最值这个问题就用表维护就可以。

然后再看最大值减掉最小值严格大于,如果在这个区间符合要求,那么是不是在这些右区间都是合法的,因为随着数的加入,区间最大值一定不会变小,区间最小值一定不会变大,所以并不会变得不符合要求。

那么我们从左到右枚举,可以看出这个也是单调的,我们用表维护这个就可以了。

时间复杂度

const int N = 1e5 + 7;

int st1[N][21], st2[N][21], Log2[N], a[N];

void pre() {
    Log2[1] = 0;
    Log2[2] = 1;
    for (int i = 3; i < N; ++i)    Log2[i] = Log2[i >> 1] + 1;
}

int queryMax(int l, int r) {
    int s = Log2[r - l + 1];
    return max(st1[l][s], st1[r - (1 << s) + 1][s]);
}

int queryMin(int l, int r) {
    int s = Log2[r - l + 1];
    return min(st2[l][s], st2[r - (1 << s) + 1][s]);
}

void sol() {
    pre();
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i)   a[i] = st1[i][0] = st2[i][0] = read();
    int t = Log2[n]; //区间最长的2次方
    for (int j = 1; j <= t; ++j)
        for (int i = 1; i + (1 << j) - 1 <= n; ++i)
            st1[i][j] = max(st1[i][j - 1], st1[i + (1 << (j - 1))][j - 1]),
            st2[i][j] = min(st2[i][j - 1], st2[i + (1 << (j - 1))][j - 1]);
    while (m--) {
        int k = read();
        ll ans = 0;
        int r = 1;
        for (int i = 1; i <= n; ++i) {
            while (r <= n && queryMax(i, r) - queryMin(i, r) <= k)
                ++r;
            if (r == n + 1)    break;
            //cout << r << endl;
            ans += n - r + 1;
        }
        print(ans);
    }
}