kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

DSL_2_C: Range Search (kD Tree) (続き5)

ということで解説を読む
kDっていうのはk次元ってことだったのか

ふむ
同じなのはたてよこあみだくじを作る、っていう全体の方針くらいだなあ
あとはかなり違う

インプレースにソートしてる
逆にいうとソートはしてる
パーティションに分けたりはしていない

領域の管理はしていない
ただ点を管理しているだけ
そう思って見てみると領域は不要どころか、
境界線上の点がどっちの領域に入るかをちゃんとしとかなきゃいけなくて
かえってめんどくさくなってたり

自分でアルゴリズムを書いたら、もっと削れないか考えるようにしたほうがよさそうだ

じゃあ書いてみよう

あっ
pythonで普通に書くと、配列の一部をインプレースにソートするってできなくない?

>>> a
>>> a=[3,2,4,1,5,0]
>>> a
[3, 2, 4, 1, 5, 0]
>>> a[0:2].sort()
>>> a
[3, 2, 4, 1, 5, 0]

だよねー

>>> a[0:2]=sorted(a[0:2])
>>> a
[2, 3, 4, 1, 5, 0]

これで近似だな

from sys import stdin, setrecursionlimit

class Node():
    def __init__(self):
        self.location = None
        self.p = self.l = self.r = None

class Point():
    MAX = 1000000

    def __init__(self, id=None, x=None, y=None):
        self.id = id
        self.x = x
        self.y = y

    def __lt__(self, other):
        return self.id < other.id

np = 0
P = []
T = []

def read_points():
    global P, T

    n = int(stdin.readline())
    for i in range(n):
        x, y = [int(x) for x in stdin.readline().split()]
        P.append(Point(i, x, y))
        T.append(Node())
    return n

def make_kd_tree(l, r, depth):
    global np, P, T

    if l >= r:
        return None

    mid = (l + r) // 2
    t = np
    np += 1

    if depth % 2 == 0:
        P[l:r] = sorted(P[l:r], key=lambda p: p.x)
    else:
        P[l:r] = sorted(P[l:r], key=lambda p: p.y)
    T[t].location = mid
    T[t].l = make_kd_tree(l, mid, depth + 1)
    T[t].r = make_kd_tree(mid + 1, r, depth + 1)

    return t

def find(v, sx, tx, sy, ty, depth, ans):
    global P, T

    x = P[T[v].location].x
    y = P[T[v].location].y

    if sx <= x <= tx and sy <= y <= ty:
        ans.append(P[T[v].location])

    if depth % 2 == 0:
        if T[v].l is not None:
            if sx <= x:
                find(T[v].l, sx, tx, sy, ty, depth + 1, ans)
        if T[v].r is not None:
            if x <= tx:
                find(T[v].r, sx, tx, sy, ty, depth + 1, ans)
    else:
        if T[v].l is not None:
            if sy <= y:
                find(T[v].l, sx, tx, sy, ty, depth + 1, ans)
        if T[v].r is not None:
            if y <= ty:
                find(T[v].r, sx, tx, sy, ty, depth + 1, ans)

def process_queries(root):
    global P

    q = int(stdin.readline())
    for i in range(q):
        sx, tx, sy, ty = [int(x) for x in stdin.readline().split()]
        ans = []
        find(root, sx, tx, sy, ty, 0, ans)
        [print(a.id) for a in sorted(ans)]
        print()

def main():
    setrecursionlimit(100)
    n = read_points()
    root = make_kd_tree(0, n, 0)
    process_queries(root)

if __name__ == '__main__':
    main()

Case#12が1.66s (AC)
Case#13が7.34s (TLE)

速くはなったけどまだ#13を超えられないか
インプレースにソートできてないのが影響してるのかもともと遅いのか
C++のコードのままグローバル変数を使っちゃったのもちょっと
遅くしてると思うけど