Skip to content

Segment Tree

P732, Leetcode

My Calendar III needs to find the maximum number of concurrent events at any time. We can solve this problem by using a segment tree.

Examples:

plaintext
Time:        5         10         15         20         40         50         60
Events:      |----------[5,15)-----|
                       |----------[10,20)------|
                       |------------------[10,40)--------|
                                                                   |--[50,60)--|
Overlaps:        1         3           2             1                   1

Implementation

rust
struct MyCalendarThree {
    tree: Node,
}

impl MyCalendarThree {
    const N: usize = 1e9 as usize;

    fn new() -> Self {
        Self {
            tree: Node::new(0, MyCalendarThree::N),
        }
    }

    fn book(&mut self, start_time: i32, end_time: i32) -> i32 {
        let l = start_time as usize;
        let r = end_time as usize - 1;
        self.tree.update(l, r, 1);
        self.tree.query(0, MyCalendarThree::N) as i32
    }
}

/// Segment Tree Node
struct Node {
    l: usize,
    r: usize,
    mid: usize,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
    v: usize,
    lazy: usize, // lazy updated to children
}

impl Node {
    /// Represents `[l, r]` not `[l, r)`
    fn new(l: usize, r: usize) -> Self {
        Self {
            l,
            r,
            mid: (l + r) >> 1,
            left: None,
            right: None,
            v: 0,
            lazy: 0,
        }
    }

    fn update(&mut self, l: usize, r: usize, v: usize) {
        if l > r {
            return;
        }

        if l <= self.l && self.r <= r {
            self.v += v;
            self.lazy += v; // record lazy value that may update to children when pushdown
            return;
        }

        self.pushdown();

        if l <= self.mid {
            self.left_mut().update(l, r, v);
        }
        if r > self.mid {
            self.right_mut().update(l, r, v);
        }

        self.pushup();
    }

    fn query(&mut self, l: usize, r: usize) -> usize {
        if l > r {
            return 0;
        }

        if l <= self.l && self.r <= r {
            return self.v;
        }

        self.pushdown();

        let mut v = 0;
        if l <= self.mid {
            v = v.max(self.left_mut().query(l, r));
        }
        if r > self.mid {
            v = v.max(self.right_mut().query(l, r));
        }
        v
    }

    fn pushup(&mut self) {
        // Update according to specific problem
        self.v = self.left_mut().v.max(self.right_mut().v)
    }

    fn pushdown(&mut self) {
        if self.lazy != 0 {
            self.left_mut().v += self.lazy;
            self.right_mut().v += self.lazy;
            self.left_mut().lazy += self.lazy;
            self.right_mut().lazy += self.lazy;
            self.lazy = 0; // Has been updated to children, reset
        }
    }

    fn right_mut(&mut self) -> &mut Node {
        self.right
            .get_or_insert_with(|| Box::new(Node::new(self.mid + 1, self.r)))
            .as_mut()
    }

    fn left_mut(&mut self) -> &mut Node {
        self.left
            .get_or_insert_with(|| Box::new(Node::new(self.l, self.mid)))
            .as_mut()
    }
}

Complexity

  • Time complexity: O(nlogN) for each query or update operation.
  • Space complexity: O(nlogN) for the segment tree.

Last updated at: