Problem:


Score : 400 points

Problem Statement

You are given a sequence A_1, A_2, ..., A_N and an integer K.

Print the maximum possible length of a sequence B that satisfies the following conditions:

B is a (not necessarily continuous) subsequence of A.

For each pair of adjacents elements of B, the absolute difference of the elements is at most K.

Constraints

1 \leq N \leq 300,000

0 \leq A_i \leq 300,000

0 \leq K \leq 300,000

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
A_1
A_2
:
A_N

Output

Print the answer.

Sample Input 1

10 3
1
5
4
3
8
6
9
7
2
4

Sample Output 1

7

For example, B = (1, 4, 3, 6, 9, 7, 4) satisfies the conditions.

It is a subsequence of A = (1, 5, 4, 3, 8, 6, 9, 7, 2, 4).

All of the absolute differences between two adjacent elements (|1-4|, |4-3|, |3-6|, |6-9|, |9-7|, |7-4|) are at most K = 3.



Sample input:
10 3
1
5
4
3
8
6
9
7
2
4


Sample output:
7

Submission status: Accepted

Solution code:
import sys
import heapq, math
from itertools import zip_longest, permutations, combinations, combinations_with_replacement
from itertools import accumulate, dropwhile, takewhile, groupby
from functools import lru_cache
from copy import deepcopy


def input():
    return sys.stdin.readline()[:-1]


class SegmentTree:

    def __init__(self, n, fn=lambda x, y: min(x, y), unity=(1 << 31) - 1):
        self.n = 1
        while self.n < n:
            self.n *= 2

        self.arr = [unity] * (2 * self.n - 1)
        self.fn = fn
        self.unity = unity

    def update(self, i, x):
        k = self.n + i
        self.arr[k] = x

        while k > 0:
            k >>= 1
            self.arr[k] = self.fn(self.arr[2 * k], self.arr[2 * k + 1])

    def query(self, l, r):
        l += self.n
        r += self.n
        lres, rres = self.unity, self.unity
        while l < r:
            # lが奇数ならば、dat[l]を加算
            if l & 1:
                lres = self.fn(lres, self.arr[l])
                l += 1

            # rが奇数ならば、dat[r-1]を加算
            if r & 1:
                r -= 1
                rres = self.fn(rres, self.arr[r])

            # 木をのぼる
            l >>= 1
            r >>= 1

        return self.fn(lres, rres)




    def __str__(self):
        return self.arr[0: 2 * self.n].__str__()


N, K = map(int, input().split())
MAX = 300000

st = SegmentTree(MAX + 10, fn=lambda x, y: max(x, y), unity=0)
ans = 0

while N > 0:
    A = int(input())
    minimum, maximum = max(A - K, 0), min(A + K, MAX)
    x = st.query(minimum, maximum + 1) + 1
    ans = max(ans, x)
    st.update(A, x)
    N -= 1

print(ans)

Submission status: Accepted

Solution code:
from sys import stdin
input = stdin.readline
class LazySegmentTree():
    def __init__(self, n, init, merge_func=min, ide_ele=10 ** 18):
        self.n = (n - 1).bit_length()
        self.merge_func = merge_func
        self.ide_ele = ide_ele
        self.data = [0 for i in range(1 << (self.n + 1))]
        self.lazy = [0 for i in range(1 << (self.n + 1))]
        for i in range(n):
            self.data[2 ** self.n + i] = init[i]
        for i in range(2 ** self.n - 1, 0, -1):
            self.data[i] = self.merge_func(self.data[2 * i], self.data[2 * i + 1])

    def propagate_above(self, i):
        m = i.bit_length() - 1
        for bit in range(m, 0, -1):
            v = i >> bit
            add = self.lazy[v]
            self.lazy[v] = 0
            self.data[2 * v] += add
            self.data[2 * v + 1] += add
            self.lazy[2 * v] += add
            self.lazy[2 * v + 1] += add

    def remerge_above(self, i):
        while i:
            i >>= 1
            self.data[i] = self.merge_func(self.data[2 * i], self.data[2 * i + 1]) + self.lazy[i]

    def update(self, l, r, x):
        l += 1 << self.n
        r += 1 << self.n
        l0 = l // (l & -l)
        r0 = r // (r & -r) - 1
        while l < r:
            self.data[l] += x * (l & 1)
            self.lazy[l] += x * (l & 1)
            l += (l & 1)
            self.data[r - 1] += x * (r & 1)
            self.lazy[r - 1] += x * (r & 1)
            l >>= 1
            r >>= 1
        self.remerge_above(l0)
        self.remerge_above(r0)

    def query(self, l, r):
        l += 1 << self.n
        r += 1 << self.n
        l0 = l // (l & -l)
        r0 = r // (r & -r) - 1
        self.propagate_above(l0)
        self.propagate_above(r0)
        res = self.ide_ele
        while l < r:
            if l & 1:
                res = self.merge_func(res, self.data[l])
                l += 1
            if r & 1:
                res = self.merge_func(res, self.data[r - 1])
            l >>= 1
            r >>= 1
        return res
def solve():
    n,k = map(int,input().split())
    a = [int(inp) for inp in stdin.read().splitlines()]
    N = 300010
    cnt = [0]* N
    LST = LazySegmentTree(N,cnt,max,-1)
    res = 0
    for i in a:
        v = LST.query(max(0,i - k),min(N,i+k) + 1)
        res = max(res,v + 1)
        cur = LST.query(i,i+1)
        LST.update(i,i+1,v+1-cur)
    print(res)


if __name__ == '__main__':
    solve()

Submission status: Accepted

Solution code:
import sys, bisect, math, itertools, string, queue, copy
# import numpy as np
# import scipy
# from collections import Counter,defaultdict,deque
# from itertools import permutations, combinations
# from heapq import heappop, heappush
# # input = sys.stdin.readline
# sys.setrecursionlimit(10**8)
mod = 10**9+7
def inp(): return int(input())
def inpm(): return map(int,input().split())
def inpl(): return list(map(int, input().split()))
def inpls(): return list(input().split())
def inplm(n): return list(int(input()) for _ in range(n))
def inplL(n): return [list(input()) for _ in range(n)]
def inplT(n): return [tuple(input()) for _ in range(n)]
def inpll(n): return [list(map(int, input().split())) for _ in range(n)]
def inplt(n): return [tuple(map(int, input().split())) for _ in range(n)]
def inplls(n): return sorted([list(map(int, input().split())) for _ in range(n)])

#####segfunc#####
def segfunc(x, y):
    return max(x,y)
#################

#####ide_ele#####
ide_ele = 0
#################

class SegTree:
    """
    init(init_val, ide_ele): 配列init_valで初期化 O(N)
    update(k, x): k番目の値をxに更新 O(logN)
    query(l, r): 区間[l, r)をsegfuncしたものを返す O(logN)
    """
    def __init__(self, init_val, segfunc, ide_ele):
        """
        init_val: 配列の初期値
        segfunc: 区間にしたい操作
        ide_ele: 単位元
        n: 要素数
        num: n以上の最小の2のべき乗
        tree: セグメント木(1-index)
        """
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        # 配列の値を葉にセット
        for i in range(n):
            self.tree[self.num + i] = init_val[i]
        # 構築していく
        for i in range(self.num - 1, 0, -1):
            self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

    def update(self, k, x):
        """
        k番目の値をxに更新
        k: index(0-index)
        x: update value
        """
        k += self.num
        self.tree[k] = x
        while k > 1:
            self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
            k >>= 1

    def query(self, l, r):
        """
        [l, r)のsegfuncしたものを得る
        l: index(0-index)
        r: index(0-index)
        """
        res = self.ide_ele

        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                res = self.segfunc(res, self.tree[l])
                l += 1
            if r & 1:
                res = self.segfunc(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res

n,k = inpm()
A = inplm(n)

seg = SegTree([0]*300001, segfunc, ide_ele)

for a in A:
    seg.update(a,seg.query(max(0,a-k),min(300001,a+k+1)) + 1)

print(seg.query(0,300001))

Submission status: Accepted

Solution code:
import sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    import os
    import re
    with open(__file__) as f:
        source = f.read().split('###''nbacl')
    for s in source[1:]:
        s = re.sub("'''.*", '', s)
        sp = s.split(maxsplit=1)
        if os.path.dirname(sp[0]):
            os.makedirs(os.path.dirname(sp[0]), exist_ok=True)
        with open(sp[0], 'w') as f:
            f.write(sp[1])
    from nbmodule import cc
    cc.compile()
import numpy as np
from numpy import int64
from nbmodule import solve


f = open(0)
N, K = [int(x) for x in f.readline().split()]
A = np.fromstring(f.read(), dtype=int64, sep=' ')
ans = solve(N, K, A)
print(ans)

'''
###nbacl nbmodule.py
import numpy as np
from numpy import int64
from numba import njit
from numba.types import i8
from numba.pycc import CC
import nbacl.segtree as seg
cc = CC('nbmodule')


@cc.export('solve', (i8, i8, i8[:]))
@njit
def solve(N, K, A):
    dp = np.zeros(300_001, dtype=int64)
    d = seg.segtree(dp, max, 0)
    for i in range(N):
        x = seg.prod(d, max, (A[i] - K) if A[i] > K else 0, (A[i] + K + 1) if A[i] + K < 300_000 else 300_001) + 1
        seg.set(d, max, A[i], x)
    return seg.all_prod(d)


if __name__ == '__main__':
    cc.compile()
###nbacl nbacl/segtree.py
import numpy as np
from numba import njit
from numba.types import i8


@njit
def ceil_pow2(n):
    x = 0
    while (1 << x) < n:
        x += 1
    return x


@njit
def segtree(a, op, e):
    log = ceil_pow2(a.shape[0])
    size = 1 << log
    d = np.empty(size * 2, dtype=a.dtype)
    d[size:size + len(a)] = a
    d[size + len(a):] = e
    # e
    d[0] = e
    for i in range(size - 1, 0, -1):
        update(d, i, op)
    return d


@njit
def update(d, k, op):
    d[k] = op(d[2 * k], d[2 * k + 1])


@njit
def set(d, op, p, x):
    p += d.shape[0] // 2
    d[p] = x
    while p > 1:
        p >>= 1
        update(d, p, op)


@njit
def get(d, p):
    return d[p + d.shape[0] // 2]


@njit
def prod(d, op, left, right):
    size = d.shape[0] // 2
    sml = d[0]
    smr = d[0]
    left += size
    right += size

    while left < right:
        if left & 1:
            sml = op(sml, d[left])
            left += 1
        if right & 1:
            right -= 1
            smr = op(d[right], smr)
        left >>= 1
        right >>= 1

    return op(sml, smr)


@njit
def all_prod(d):
    return d[1]

'''

Submission status: Accepted

Solution code:
import sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    import os
    import re
    with open(__file__) as f:
        source = f.read().split('###''nbacl')
    for s in source[1:]:
        s = re.sub("'''.*", '', s)
        sp = s.split(maxsplit=1)
        if os.path.dirname(sp[0]):
            os.makedirs(os.path.dirname(sp[0]), exist_ok=True)
        with open(sp[0], 'w') as f:
            f.write(sp[1])
    from nbmodule import cc
    cc.compile()
import numpy as np
from numpy import int64
from nbmodule import solve


f = open(0)
N, K = [int(x) for x in f.readline().split()]
A = np.fromstring(f.read(), dtype=int64, sep=' ')
ans = solve(N, K, A)
print(ans)

'''
###nbacl nbmodule.py
import numpy as np
from numpy import int64
from numba import njit
from numba.types import i8
from numba.pycc import CC
import nbacl.segtree as seg
cc = CC('my_module')


@cc.export('solve', (i8, i8, i8[:]))
@njit
def solve(N, K, A):
    dp = np.zeros(300_001, dtype=int64)
    d = seg.segtree(dp, max, 0)
    for i in range(N):
        x = seg.prod(d, max, (A[i] - K) if A[i] > K else 0, (A[i] + K + 1) if A[i] + K < 300_000 else 300_001) + 1
        seg.set(d, max, A[i], x)
    return seg.all_prod(d)


if __name__ == '__main__':
    cc.compile()
###nbacl nbacl/segtree.py
import numpy as np
from numba import njit
from numba.types import i8


@njit
def ceil_pow2(n):
    x = 0
    while (1 << x) < n:
        x += 1
    return x


@njit
def segtree(a, op, e):
    log = ceil_pow2(a.shape[0])
    size = 1 << log
    d = np.empty(size * 2, dtype=a.dtype)
    d[size:size + len(a)] = a
    d[size + len(a):] = e
    # e
    d[0] = e
    for i in range(size - 1, 0, -1):
        update(d, i, op)
    return d


@njit
def update(d, k, op):
    d[k] = op(d[2 * k], d[2 * k + 1])


@njit
def set(d, op, p, x):
    p += d.shape[0] // 2
    d[p] = x
    while p > 1:
        p >>= 1
        update(d, p, op)


@njit
def get(d, p):
    return d[p + d.shape[0] // 2]


@njit
def prod(d, op, left, right):
    size = d.shape[0] // 2
    sml = d[0]
    smr = d[0]
    left += size
    right += size

    while left < right:
        if left & 1:
            sml = op(sml, d[left])
            left += 1
        if right & 1:
            right -= 1
            smr = op(d[right], smr)
        left >>= 1
        right >>= 1

    return op(sml, smr)


@njit
def all_prod(d):
    return d[1]

'''

Submission status: Accepted

Solution code:
import sys
if sys.argv[-1] == 'ONLINE_JUDGE':
    import os
    import re
    with open(__file__) as f:
        source = f.read().split('###''nbacl')
    for s in source[1:]:
        s = re.sub("'''.*", '', s)
        sp = s.split(maxsplit=1)
        if os.path.dirname(sp[0]):
            os.makedirs(os.path.dirname(sp[0]), exist_ok=True)
        with open(sp[0], 'w') as f:
            f.write(sp[1])
import numpy as np
from numpy import int64
from numba import njit
from numba.types import i8
import nbacl.segtree as seg


@njit((i8, i8, i8[:]), cache=True)
def solve(N, K, A):
    dp = np.zeros(300_001, dtype=int64)
    d = seg.segtree(dp, max, 0)
    for i in range(N):
        x = seg.prod(d, max, (A[i] - K) if A[i] > K else 0, (A[i] + K + 1) if A[i] + K < 300_000 else 300_001) + 1
        seg.set(d, max, A[i], x)
    return seg.all_prod(d)


f = open(0)
N, K = [int(x) for x in f.readline().split()]
A = np.fromstring(f.read(), dtype=int64, sep=' ')
ans = solve(N, K, A)
print(ans)

'''
###nbacl nbacl/segtree.py
import numpy as np
from numba import njit
from numba.types import i8


@njit
def ceil_pow2(n):
    x = 0
    while (1 << x) < n:
        x += 1
    return x


@njit
def segtree(a, op, e):
    log = ceil_pow2(a.shape[0])
    size = 1 << log
    d = np.empty(size * 2, dtype=a.dtype)
    d[size:size + len(a)] = a
    d[size + len(a):] = e
    # e
    d[0] = e
    for i in range(size - 1, 0, -1):
        update(d, i, op)
    return d


@njit
def update(d, k, op):
    d[k] = op(d[2 * k], d[2 * k + 1])


@njit
def set(d, op, p, x):
    p += d.shape[0] // 2
    d[p] = x
    while p > 1:
        p >>= 1
        update(d, p, op)


@njit
def get(d, p):
    return d[p + d.shape[0] // 2]


@njit
def prod(d, op, left, right):
    size = d.shape[0] // 2
    sml = d[0]
    smr = d[0]
    left += size
    right += size

    while left < right:
        if left & 1:
            sml = op(sml, d[left])
            left += 1
        if right & 1:
            right -= 1
            smr = op(d[right], smr)
        left >>= 1
        right >>= 1

    return op(sml, smr)


@njit
def all_prod(d):
    return d[1]

'''

Submission status: Accepted

Solution code:
#####segfunc######                                                              
def segfunc(x,y):
    return max(x,y)

def init(init_val):
    #set_val                                                                    
    for i in range(n):
        seg[i+num-1]=init_val[i]
    #built                                                                      
    for i in range(num-2,-1,-1):
        seg[i]=segfunc(seg[2*i+1],seg[2*i+2])
    
def update(k,x):
    k+=num-1
    seg[k]=x
    while k+1:
        k=(k-1)//2
        seg[k]=segfunc(seg[k*2+1],seg[k*2+2])

def query(p,q):
    if q<=p:
        return ide_ele
    p+=num-1
    q+=num-2
    res=ide_ele
    while q-p>1:
        if p&1==0:
            res=segfunc(res,seg[p])
        if q&1==1:
            res=segfunc(res,seg[q])
            q-=1
        p=p//2
        q=(q-1)//2
    if p==q:
        res=segfunc(res,seg[p])
    else:
        res=segfunc(segfunc(res,seg[p]),seg[q])
    return res

ide_ele=0
N,K=map(int,input().split())
n=300001
num=2**(n-1).bit_length()
seg=[ide_ele]*2*num
init([0]*300001)
for i in range(N):
    A = int(input())
    a = max(A-K, 0)
    b = min(A+K, 300000)
    tmp = query(a, b+1) + 1
    update(A, tmp)
print(query(0, 300000))

Submission status: Accepted

Solution code:
class SegmentTree():
    '''
    非再帰
    segment tree
    '''

    def __init__(self, n, func, init=float('inf')):
        '''
        n->配列の長さ
        func:func(a,b)->val,　func=minだとRMQになる
        木の高さhとすると,
        n:h-1までのノード数。h段目のノードにアクセスするために使う。
        data:ノード。data[0]:root<-leaf:data[-1]
        parent:k->child k*2+1とk*2+2
        '''
        self.n = 2**(n-1).bit_length()
        self.init = init
        self.data = [init]*(2*self.n)
        self.func = func

    def set(self, i, v):
        '''
        leafの初期化
        i: 0-origin idx
        v: value
        '''
        self.data[i+self.n-1] = v

    def build(self):
        '''
        setの後に一斉更新
        '''
        #leaf->rootに向かって、apply func していく
        for k in reversed(range(self.n-1)):
            self.data[k] = self.func(self.data[k*2+1], self.data[k*2+2])

    def update(self, k, a):
        '''
        data[k]=aに更新する。
        更新をrootまで更新
        '''
        k += self.n-1 #k=segTree上での k-th leafのidx
        self.data[k] = a

        while k > 0: #while not reach to root
            k = (k-1)//2 #goto its parent
            self.data[k] = self.func(self.data[k*2+1], self.data[k*2+2]) #update

    def query(self, l, r):
        '''
        [l,r)のfuncを求める
        '''
        L = l+self.n
        R = r+self.n
        ret = self.init
        while L < R:
            if R & 1: #R%2==1 
                R -= 1
                ret = self.func(ret, self.data[R-1]) #親が丸々区間に含まれない->はみ出したところを更新
            if L & 1:
                ret = self.func(ret, self.data[L-1])
                L += 1
            L >>= 1 #to parent
            R >>= 1
        return ret


    def lower_bound_index(self,x,v):
        """
        x:0-origin
        [x,N)の範囲で、v<=data[j]を満たす最小のjを探す(二分探索)

        存在しないなら、float("inf")をreturn している。
        """
        #区間の左端
        x+=self.n-1

        #data[x]が、v以上なるまで登る
        while self.data[x]<v:
            if x%2==0: #xが右のnodeなら、候補外になる
                if len(bin(x+1))==len(bin(x+2)):#一つ右に移動できるなら
                    x+=1
                else:#右に行けない->とりま大きい値をreturnしとく。(多分、全ての値が条件を満たさない時に、無限whileするのを防ぐ
                    return float("inf")

            else:#登る
                x>>=1

        # v<=data[x]を満たすように、できるだけ左(idxが小さい)に降る
        while x<self.n-1:#どこかの葉にたどり着くまで
            if self.data[2*x+1]>=v:#左の子が v<=data[x]を満たすなら、優先して左に。
                x=2*x+1
            else:#シャーなしの右
                x=2*x+2
        return x-self.n+1 #seg木のidxから、元のlistのidxに変換


N,K = map(int,input().split())
A=[int(input()) for _ in range(N)]

Seg=SegmentTree(300005, lambda a,b:max(a,b),0)

ans=0
for a in A:
    tmp = Seg.query(max(a-K,0),min(300005,a+K)+1)

    tmp+=1
    Seg.update(a,tmp)
    ans = max(tmp,ans)
print(ans)

Submission status: Accepted

Solution code:
def segfunc(x, y): return max(x, y)
def update(i, x):
    i += MAX_N-1
    node[i] = x
    while i:
        i = (i-1)//2
        node[i] = segfunc(node[i*2+1], node[i*2+2])

def query(l, r):
    L = l + MAX_N
    R = r + MAX_N
    s = INF
    while L < R:
        if R & 1:
            R -= 1
            s = segfunc(s, node[R - 1])
        if L & 1:
            s = segfunc(s, node[L - 1])
            L += 1
        L >>= 1
        R >>= 1
    return s

N, K = map(int, input().split())
MAX_N = 2**(300005).bit_length()
a = [int(input()) for _ in range(N)]
node = [0] * (2 * MAX_N)
INF = 0
ans = 0

#for i in range(N):
#    update(i, a[i])

for i in a:
    tmp = query(max(i - K, 0), min(300005, i + K) + 1)
    update(i, tmp + 1)
    ans = max(ans, tmp + 1)
print(ans)

Submission status: Accepted

Solution code:
m,k=map(int,input().split())

n=300005

def init_max(init_max_val):
    #set_val
    for i in range(n):
        seg_max[i+num_max-1]=init_max_val[i]    
    #built
    for i in range(num_max-2,-1,-1) :
        seg_max[i]=max(seg_max[2*i+1],seg_max[2*i+2]) 
    
def update_max(k,x):
    k += num_max-1
    seg_max[k] = x
    while k:
        k = (k-1)//2
        seg_max[k] = max(seg_max[k*2+1],seg_max[k*2+2])
    
def query_max(p,q):
    if q<=p:
        return ide_ele_max
    p += num_max-1
    q += num_max-2
    res=ide_ele_max
    while q-p>1:
        if p&1 == 0:
            res = max(res,seg_max[p])
        if q&1 == 1:
            res = max(res,seg_max[q])
            q -= 1
        p = p//2
        q = (q-1)//2
    if p == q:
        res = max(res,seg_max[p])
    else:
        res = max(max(res,seg_max[p]),seg_max[q])
    return res

#####単位元######
ide_ele_max = 0

#num_max:n以上の最小の2のべき乗
num_max =2**(n-1).bit_length()
seg_max=[ide_ele_max]*2*num_max

for _ in range(m):
    a=int(input())
    maxl=query_max(max(0,a-k),min(n-1,a+k)+1)
    update_max(a,maxl+1)

print(query_max(0,n+1))

Submission status: Accepted

Solution code:
import sys

# from https://github.com/not522/ac-library-python
### ACL ###
import typing
 
def _ceil_pow2(n: int) -> int:
    x = 0
    while (1 << x) < n:
        x += 1
 
    return x
 
 
def _bsf(n: int) -> int:
    x = 0
    while n % 2 == 0:
        x += 1
        n //= 2
 
    return x
 
class SegTree:
    def __init__(self,
                 op: typing.Callable[[typing.Any, typing.Any], typing.Any],
                 e: typing.Any,
                 v: typing.Union[int, typing.List[typing.Any]]) -> None:
        self._op = op
        self._e = e
 
        if isinstance(v, int):
            v = [e] * v
 
        self._n = len(v)
        # self._log = atcoder._bit._ceil_pow2(self._n)
        self._log = _ceil_pow2(self._n)
        self._size = 1 << self._log
        self._d = [e] * (2 * self._size)
 
        for i in range(self._n):
            self._d[self._size + i] = v[i]
        for i in range(self._size - 1, 0, -1):
            self._update(i)
 
    def set(self, p: int, x: typing.Any) -> None:
        assert 0 <= p < self._n
 
        p += self._size
        self._d[p] = x
        for i in range(1, self._log + 1):
            self._update(p >> i)
 
    def get(self, p: int) -> typing.Any:
        assert 0 <= p < self._n
 
        return self._d[p + self._size]
 
    def prod(self, left: int, right: int) -> typing.Any:
        assert 0 <= left <= right <= self._n
        sml = self._e
        smr = self._e
        left += self._size
        right += self._size
 
        while left < right:
            if left & 1:
                sml = self._op(sml, self._d[left])
                left += 1
            if right & 1:
                right -= 1
                smr = self._op(self._d[right], smr)
            left >>= 1
            right >>= 1
 
        return self._op(sml, smr)
 
    def all_prod(self) -> typing.Any:
        return self._d[1]
 
    def max_right(self, left: int,
                  f: typing.Callable[[typing.Any], bool]) -> int:
        assert 0 <= left <= self._n
        assert f(self._e)
 
        if left == self._n:
            return self._n
 
        left += self._size
        sm = self._e
 
        first = True
        while first or (left & -left) != left:
            first = False
            while left % 2 == 0:
                left >>= 1
            if not f(self._op(sm, self._d[left])):
                while left < self._size:
                    left *= 2
                    if f(self._op(sm, self._d[left])):
                        sm = self._op(sm, self._d[left])
                        left += 1
                return left - self._size
            sm = self._op(sm, self._d[left])
            left += 1
 
        return self._n
 
    def min_left(self, right: int,
                 f: typing.Callable[[typing.Any], bool]) -> int:
        assert 0 <= right <= self._n
        assert f(self._e)
 
        if right == 0:
            return 0
 
        right += self._size
        sm = self._e
 
        first = True
        while first or (right & -right) != right:
            first = False
            right -= 1
            while right > 1 and right % 2:
                right >>= 1
            if not f(self._op(self._d[right], sm)):
                while right < self._size:
                    right = 2 * right + 1
                    if f(self._op(self._d[right], sm)):
                        sm = self._op(self._d[right], sm)
                        right -= 1
                return right + 1 - self._size
            sm = self._op(self._d[right], sm)
 
        return 0
 
    def _update(self, k: int) -> None:
        self._d[k] = self._op(self._d[2 * k], self._d[2 * k + 1])
 
### ACL ###

input = sys.stdin.readline
 
N, K = map(int, input().split())
A = []
for _ in range(N):
    A.append(int(input()))

MAX_A = 3*10**5+5
# (i番目までを使ったときの）末尾がaの部分列の長さ
dp = [0 for _ in range(MAX_A)]
segtree = SegTree(max, 0, [0] * MAX_A)
for i in range(N):
    x = A[i]
    l = max(0, x-K)
    r = min(MAX_A, x+K+1)
    now = segtree.prod(l, r) + 1
    segtree.set(x, now)
 
print(segtree.prod(0, MAX_A))

Submission status: Accepted

Solution code:
from collections import deque
INFTY = 10**10
def update(i,a):
    j = i+N
    T[j] = a
    j = j//2
    while j>=1:
        T[j]=max(T[2*j],T[2*j+1])
        j = j//2
def find(l,r):
    que = deque([(1,0,N)])
    A = []
    while que:
        j,x,D = que.popleft()
        y = x+D
        if y<=l or x>=r:
            A.append(-INFTY)
        elif l<=x and y<=r:
            A.append(T[j])
        else:
            que.append((2*j,x,D//2))
            que.append((2*j+1,x+D//2,D//2))
    return max(A)
n,K = map(int,input().split())
A = [int(input()) for _ in range(n)]
k = 0
while 2**k<3*10**5:
    k += 1
N = 2**k
T = [-INFTY for _ in range(2*N)]
dp = [0 for _ in range(n)]
dp[0]=1
update(A[0],dp[0])
for i in range(1,n):
    a = A[i]
    l = max(0,a-K)
    r = min(a+K,N-1)+1
    dp[i] = max(1,find(l,r)+1)
    update(a,dp[i])
dmax = 0
for i in range(n):
    dmax = max(dmax,dp[i])
print(dmax)

Submission status: Accepted

Solution code:
n,k=map(int,input().split())
a=[]
for i in range(n):
    a.append(int(input()))
dp=[0]*(300010)

#####segfunc#####
def segfunc(x, y):
    return max(x,y)
#################

#####ide_ele#####
ide_ele =0
#################

class SegTree:
    """
    init(init_val, ide_ele): 配列init_valで初期化 O(N)
    update(k, x): k番目の値をxに更新 O(logN)
    query(l, r): 区間[l, r)をsegfuncしたものを返す O(logN)
    """
    def __init__(self, init_val, segfunc, ide_ele):
        """
        init_val: 配列の初期値
        segfunc: 区間にしたい操作
        ide_ele: 単位元
        n: 要素数
        num: n以上の最小の2のべき乗
        tree: セグメント木(1-index)
        """
        n = len(init_val)
        self.segfunc = segfunc
        self.ide_ele = ide_ele
        self.num = 1 << (n - 1).bit_length()
        self.tree = [ide_ele] * 2 * self.num
        # 配列の値を葉にセット
        for i in range(n):
            self.tree[self.num + i] = init_val[i]
        # 構築していく
        for i in range(self.num - 1, 0, -1):
            self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

    def update(self, k, x):
        """
        k番目の値をxに更新
        k: index(0-index)
        x: update value
        """
        k += self.num
        self.tree[k] = x
        while k > 1:
            self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
            k >>= 1

    def query(self, l, r):
        """
        [l, r)のsegfuncしたものを得る
        l: index(0-index)
        r: index(0-index)
        """
        res = self.ide_ele

        l += self.num
        r += self.num
        while l < r:
            if l & 1:
                res = self.segfunc(res, self.tree[l])
                l += 1
            if r & 1:
                res = self.segfunc(res, self.tree[r - 1])
            l >>= 1
            r >>= 1
        return res

seg=SegTree(dp,segfunc,0)
for i in a:
    l=max(i-k,0)
    r=min(i+k,300005)

    dp[i]=seg.query(l,r+1)+1
    seg.update(i,dp[i])
print(max(dp))

Submission status: Accepted

Solution code:
from collections import Counter,defaultdict,deque
from heapq import heappop,heappush
from bisect import bisect_left,bisect_right 
import sys,math,itertools,fractions,pprint
sys.setrecursionlimit(10**8)
mod = 10**9+7
INF = float('inf')
def inp(): return int(sys.stdin.readline())
def inpl(): return list(map(int, sys.stdin.readline().split()))

from typing import Callable, TypeVar, List

T = TypeVar('T')
class SegTree:
    def __init__(self, v: List[T], op: Callable[[T, T], T], e: Callable[[], T]) -> None:
        self._n = len(v)
        self.log = (self._n - 1).bit_length()
        self.size = 1 << self.log
        self.d = [e() for _ in range(2 * self.size)]
        self.op = op
        self.e = e
        for i in range(self._n):
            self.d[self.size + i] = v[i]
        for i in reversed(range(1, self.size)):
            self.__update__(i)

    @classmethod
    def init_e(cls, n: int, op: Callable[[T, T], T], e: Callable[[], T]) -> 'SegTree':
        return cls([e() for _ in range(n)], op, e)

    #値代入
    def set(self, p: int, x: T) -> None:
        assert 0 <= p < self._n
        p += self.size
        self.d[p] = x
        for i in range(1, self.log + 1):
            self.__update__(p >> i)

    def get(self, p: int) -> T:
        assert 0 <= p < self._n
        return self.d[p + self.size]

    #計算 [l,r)
    def prod(self, l: int, r: int) -> T:
        assert 0 <= l <= self._n and 0 <= r <= self._n
        sml = self.e()
        smr = self.e()
        l += self.size
        r += self.size

        while l < r:
            if l & 1:
                sml = self.op(sml, self.d[l])
                l += 1
            if r & 1:
                r -= 1
                smr = self.op(self.d[r], smr)
            l >>= 1
            r >>= 1
        return self.op(sml, smr)

    def all_prod(self) -> T:
        return self.d[1]

    #f(op(a[l], a[l + 1], ..., a[r - 1])) = true となる最大のrを返す
    def max_right(self, l: int, f: Callable[[T], bool]):
        assert 0 <= l <= self._n
        assert f(self.e())
        if l == self._n:
            return self._n
        l += self.size
        sm = self.e()
        while True:
            while l % 2 == 0:
                l >>= 1
            if not f(self.op(sm, self.d[l])):
                while l < self.size:
                    l *= 2
                    if f(self.op(sm, self.d[l])):
                        sm = self.op(sm, self.d[l])
                        l += 1
                return l - self.size
            sm = self.op(sm, self.d[l])
            l += 1
            if (l & -l) == l:
                return self._n

    def min_left(self, r: int, f: Callable[[T], bool]):
        assert 0 <= r <= self._n
        assert f(self.e())
        if r == 0:
            return 0
        r += self.size
        sm = self.e()
        while True:
            r -= 1
            while r > 1 and r % 2:
                r >>= 1
            if not f(self.op(self.d[r], sm)):
                while r < self.size:
                    r = 2 * r + 1
                    if f(self.op(self.d[r], sm)):
                        sm = self.op(self.d[r], sm)
                        r -= 1
                return r + 1 - self.size
            sm = self.op(self.d[r], sm)
            if (r & -r) == r:
                return 0

    def __update__(self, k: int) -> None:
        self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])

#加算
# def op(x,y):
#     return x+y
# a = list(range(10))
# st = SegTree(a,op,lambda:0)
# st.prod(3,7) -> 3+4+5+6 = 18

#最大値
# st = SegTree(a,max,lambda:-INF)
n,k = inpl()
a = [inp() for _ in range(n)]
dp = SegTree([0]*300010, max, lambda:-1)
for i,x in enumerate(a):
    l = max(0,x-k)
    r = min(300002,x+k+1)
    now = dp.prod(l,r)
    dp.set(x, now+1)
print(dp.all_prod())