#pragma once #include #include #include #include namespace search { // SegmentTree that can be used in offline mode, when all possible // segments that will be added/removed are known in advance. // // Complexity for Add(), Erase() and Find() is O(log(n)), where n is a // total number of segments. class SegmentTree { public: auto static constexpr kNegativeInfinity = -std::numeric_limits::max(); auto static constexpr kPositiveInfinity = std::numeric_limits::max(); auto static constexpr kInvalidId = std::numeric_limits::max(); struct Segment { Segment() = default; Segment(double from, double to, size_t id) : m_from(from), m_to(to), m_id(id) {} bool operator<(Segment const & rhs) const { if (m_from != rhs.m_from) return m_from < rhs.m_from; if (m_to != rhs.m_to) return m_to < rhs.m_to; return m_id < rhs.m_id; } bool operator==(Segment const & rhs) const { return m_id == rhs.m_id && m_from == rhs.m_from && m_to == rhs.m_to; } // *NOTE* Do not change these values without care - current code // depends on default values. double m_from = kPositiveInfinity; double m_to = kPositiveInfinity; size_t m_id = kInvalidId; }; struct Node { // Segment corresponding to the node. Segment m_segment; // Maximum value among all right bounds of non-deleted segments in // the subtree. double m_to = kNegativeInfinity; // True when corresponding segment is deleted. bool m_deleted = true; }; // *NOTE* |segments| must be sorted. SegmentTree(std::vector const & segments); void Add(Segment const & segment); void Erase(Segment const & segment); // Calls |fn| on an arbitrary segment containing |x|. template void FindAny(double x, Fn && fn) const { FindAny(0 /* index */, x, fn); } // Calls |fn| on all segments containing |x| making // exactly one call per segment. template void FindAll(double x, Fn && fn) { std::vector interesting; auto const collectFn = [&](Segment const & seg) { interesting.push_back(&seg); }; while (FindAny(0 /* index */, x, collectFn)) Erase(*interesting.back()); for (auto const * p : interesting) { fn(*p); Add(*p); } } private: static size_t LeftChild(size_t index) { return 2 * index + 1; } static size_t RightChild(size_t index) { return 2 * index + 2; } bool Exists(size_t index) const { return index < m_tree.size(); } template void FindSegment(size_t index, Segment const & segment, Fn && fn); template bool FindAny(size_t index, double x, Fn & fn) const { if (!Exists(index)) return false; auto const & root = m_tree[index]; auto const & segment = root.m_segment; if (!root.m_deleted && x >= segment.m_from && x <= segment.m_to) { fn(segment); return true; } auto const lc = LeftChild(index); if (x < segment.m_from || (Exists(lc) && m_tree[lc].m_to >= x)) return FindAny(lc, x, fn); return FindAny(RightChild(index), x, fn); } void BuildTree(size_t index, std::vector const & segments, size_t left, size_t right); void Update(size_t index); std::vector m_tree; }; } // namespace search