题意:求长度为n的序列中,间隔至少为d的最长上升子序列的长度。
题解:因为n取值到1e5,到每个元素之前的最长上升子序列用线段树维护,区间内的值是在当前区间内最长上升子序列的最大长度,区间范围是给出的序列中的值确定的,f[i]存从0到a[i]的范围内的最长上升子序列的最大长度,因为间隔要大于等于d,所以第i个元素进行线段树更新节点后,f数组只更新到i-d。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
int n, d, a[N], f[N], tree[N << 2];

int query(int k, int left, int right, int l, int r) {
    if (l <= left && right <= r)
        return tree[k];
    int mid = (left + right) / 2;
    if (mid >= r)
        return query(k * 2, left, mid, l, r);
    if (mid < l)
        return query(k * 2 + 1, mid + 1, right, l, r);
    return max(query(k * 2, left, mid, l, mid), query(k * 2 + 1, mid + 1, right, mid + 1, r));
}

void modify(int k, int left, int right, int pos, int x) {
    if (left == right) {
        tree[k] = max(tree[k], x);
        return;
    }
    int mid = (left + right) / 2;
    if (pos <= mid)
        modify(k * 2, left, mid, pos, x);
    else
        modify(k * 2 + 1, mid + 1, right, pos, x);
    tree[k] = max(tree[k * 2], tree[k * 2 + 1]);
}

int main() {
    while (scanf("%d%d", &n, &d) == 2) {
        memset(tree, 0, sizeof(tree));
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        int res = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] > 0)
                res = max(res, f[i] = query(1, 0, N, 0, a[i] - 1) + 1);
            else
                res = max(res, f[i] = 1);
            if (i - d > 0)
                modify(1, 0, N, a[i - d], f[i - d]);
        }
        printf("%d\n", res);
    }
    return 0;
}