class AssociatedTree:
def __init__(self, ordered, dim, dims):
points = ordered[dim]
n = len(points)
h = (n-1) // 2
self.split = points[h][dim]
self.dim = dim
self.left = self.right = self.assoc = self.point = None
self.next = self.first = self.last = None
if n > 1:
left = [[p for p in pts if p[dim] <= self.split] for pts in ordered]
right = [[p for p in pts if p[dim] > self.split] for pts in ordered]
self.left = AssociatedTree(left, dim, dims)
self.first = self.left.first
self.right = AssociatedTree(right, dim, dims)
self.last = self.right.last
self.left.last.next = self.right.first
else:
self.point, = points
self.first = self.last = self
if dim < dims - 1:
self.assoc = AssociatedTree(ordered, dim+1, dims)
def query(self, left, right):
if self.point is not None:
if left[self.dim] <= self.split <= right[self.dim]:
yield from self.report(left, right)
return
elif right[self.dim] <= self.split:
yield from self.left.query(left, right)
elif left[self.dim] > self.split:
yield from self.right.query(left, right)
else:
yield from self.left.left_descent(left, right)
yield from self.right.right_descent(left, right)
def left_descent(self, left, right):
if self.point is not None:
if left[self.dim] <= self.split:
yield from self.report(left, right)
return
if left[self.dim] > self.split:
yield from self.right.left_descent(left, right)
else:
yield from self.left.left_descent(left, right)
yield from self.right.report(left, right)
def right_descent(self, left, right):
if self.point is not None:
if right[self.dim] >= self.split:
yield from self.report(left, right)
return
if right[self.dim] <= self.split:
yield from self.left.right_descent(left, right)
else:
yield from self.left.report(left, right)
yield from self.right.right_descent(left, right)
def report(self, left, right):
if self.assoc is not None:
yield from self.assoc.query(left, right)
else:
p = self.first
while p != self.last:
yield p.point
p = p.next
yield p.point
class RangeTree:
def __init__(self, points, dims):
assert len(points) > 0
ordered = [sorted(points, key=lambda p, i=i: p[i]) for i in range(dims)]
self.tree = AssociatedTree(ordered, 0, dims)
def query(self, left, right):
yield from self.tree.query(left, right)
We are given a set $P$ of $n$ points in a plane. We want to design a dynamic data structure which stores a subset $Q \subseteq P$. At the beginning, we have $Q = P$. The data structure should be able to perform the following operations in $O(\log^2 n)$ time:
We are given a set $P$ of $n$ points in $\mathbb{R}^d$, where $d$ is constant. We want to design a data structure which stores $P$ and allows partial queries. A partial query is given by values for a subset of coordinates, and its result is the set of points which match the given coordinates.
Example partial queries in $\mathbb{R}^3$:
inf = float('inf')
def partial_query(tree, x=None, y=None):
if x is None:
xmin = -inf
xmax = inf
else:
xmin = xmax = x
if y is None:
ymin = -inf
ymax = inf
else:
ymin = ymax = y
yield from tree.query(left=[xmin, ymin], right=[xmax, ymax])
Suppose we are given points $({x_1^{(i)}}, {x_2^{(i)}}, \dots, {x_d^{(i)}})$ ($1 \le i \le n$).
Let $H$ be a set of at most $n$ horizontal segments and let $V$ be a set of at most $n$ vertical segments. We want to find an algorithm which determines the number of intersecting pairs from $H \times V$ in $O(n \log n)$ time.