Range Module

hard design interval

Problem

addRange / queryRange / removeRange of half-open intervals.

Inputadd[10,20); query[10,14) → True; remove[14,16); query[10,14) → True
OutputTrue True
Maintain a normalized set of disjoint intervals.

from bisect import bisect_left, bisect_right, insort
class RangeModule:
    def __init__(self): self.r = []
    def addRange(self, l, r):
        i = bisect_left(self.r, l); j = bisect_right(self.r, r)
        merged = []
        if i % 2 == 1: i -= 1; merged.append(self.r[i])
        else: merged.append(l)
        if j % 2 == 1: merged.append(self.r[j]); j += 1
        else: merged.append(r)
        self.r[i:j] = merged
    def queryRange(self, l, r):
        i = bisect_right(self.r, l); j = bisect_left(self.r, r)
        return i == j and i % 2 == 1
    def removeRange(self, l, r):
        i = bisect_left(self.r, l); j = bisect_right(self.r, r)
        merged = []
        if i % 2 == 1: merged.append(l)
        if j % 2 == 1: merged.append(r)
        self.r[i:j] = merged
class RangeModule {
  constructor() { this.r = []; }
  bsl(x) { let lo = 0, hi = this.r.length; while (lo < hi) { const m = (lo + hi) >> 1; if (this.r[m] < x) lo = m + 1; else hi = m; } return lo; }
  bsr(x) { let lo = 0, hi = this.r.length; while (lo < hi) { const m = (lo + hi) >> 1; if (this.r[m] <= x) lo = m + 1; else hi = m; } return lo; }
  addRange(l, r) {
    let i = this.bsl(l), j = this.bsr(r); const m = [];
    if (i % 2 === 0) m.push(l); else { i--; m.push(this.r[i]); }
    if (j % 2 === 0) m.push(r); else { m.push(this.r[j]); j++; }
    this.r.splice(i, j - i, ...m);
  }
  queryRange(l, r) { const i = this.bsr(l), j = this.bsl(r); return i === j && i % 2 === 1; }
  removeRange(l, r) {
    const i = this.bsl(l), j = this.bsr(r); const m = [];
    if (i % 2 === 1) m.push(l);
    if (j % 2 === 1) m.push(r);
    this.r.splice(i, j - i, ...m);
  }
}
// Java implementation uses TreeMap for floor/ceiling ops on disjoint intervals.
class RangeModule {
    TreeMap ranges = new TreeMap<>();
    public void addRange(int l, int r) {
        Map.Entry lo = ranges.floorEntry(l), hi = ranges.floorEntry(r);
        if (lo != null && lo.getValue() >= l) l = lo.getKey();
        if (hi != null && hi.getValue() > r) r = hi.getValue();
        ranges.subMap(l, r).clear(); ranges.put(l, r);
    }
    public boolean queryRange(int l, int r) {
        Map.Entry e = ranges.floorEntry(l);
        return e != null && e.getValue() >= r;
    }
    public void removeRange(int l, int r) {
        Map.Entry lo = ranges.floorEntry(l), hi = ranges.lowerEntry(r);
        if (hi != null && hi.getValue() > r) ranges.put(r, hi.getValue());
        if (lo != null && lo.getValue() > l) ranges.put(lo.getKey(), l);
        ranges.subMap(l, r).clear();
    }
}
// C++ implementation uses std::map for ordered ops on disjoint intervals.
class RangeModule {
    map r;
public:
    void addRange(int l, int R) {
        auto it = r.upper_bound(l); if (it != r.begin()) { --it; if (it->second < l) ++it; }
        while (it != r.end() && it->first <= R) { l = min(l, it->first); R = max(R, it->second); it = r.erase(it); }
        r[l] = R;
    }
    bool queryRange(int l, int R) {
        auto it = r.upper_bound(l); if (it == r.begin()) return false;
        return (--it)->second >= R;
    }
    void removeRange(int l, int R) {
        auto it = r.upper_bound(l); if (it != r.begin()) { --it; if (it->second < l) ++it; }
        while (it != r.end() && it->first < R) {
            int s = it->first, e = it->second; it = r.erase(it);
            if (s < l) r[s] = l; if (e > R) r[R] = e;
        }
    }
};
Time: O(log n + k) Space: O(n)