Files
cpp-flashcards/org/segment_tree.org
T

4.8 KiB

Segment Tree

Segment

class seg_tree():
    def __init__(self, arr):
        self.n = len(arr)
        self.t = [0]*self.n + arr
        for i in range(self.n-1, -1, -1):
            self.t[i] = self.t[i<<1] + self.t[(i<<1)+1]

    def q(l, r):

class Fenwick:
    def __init__(self, lst: List[int], lamd):
        self.n = len(lst)
        self.t = [0] * self.n + lst
        print(self.t)
        for i in range(self.n-1, 1, -1):
            self.t[i] = self.t[i<<1] + self.t[(i<<1)+1]
        self.f = lamd

    def update(self, i, x):
        i += self.n
        self.t[i] = x
        while i > 1:
            self.t[i>>1] = self.t[i] + self.t[i^1]
            i >>= 1

    def query(self, lo, hi):
        ans = 0
        lo += self.n
        hi += self.n
        while lo < hi:
            if lo & 1:
                ans = min(ans, self.t[lo])
                lo += 1

            if hi & 1:
                hi -= 1
                ans = min(ans, self.t[hi])
            lo >>= 1
            hi >>= 1
        return ans
class Fenwick:
    def __init__(self, lst: list[int]):
        self.n = len(lst)
        self.t = [float('inf')] * self.n + lst
        for i in range(self.n-1, 1, -1):
            self.t[i] = min(self.t[i<<1], self.t[(i<<1)+1])
        print(self.t)

    def update(self, i, x):
        i += self.n
        self.t[i] = x
        while i > 1:
            self.t[i>>1] = self.t[i] + self.t[i^1]
            i >>= 1

    def query(self, lo, hi):
        ans = 0
        lo += self.n
        hi += self.n
        while lo < hi:
            if lo & 1:
                ans = min(ans, self.t[lo])
                lo += 1

            if hi & 1:
                hi -= 1
                ans = min(ans, self.t[hi])
            lo >>= 1
            hi >>= 1
        return ans
fw = Fenwick([999,2,1,999,999,999,999])
i = fw.query(0, 2)
print(i)
[inf, inf, 1, 999, 1, 999, 999, 999, 2, 1, 999, 999, 999, 999]
0
class Fenwick:
  def __init__(self, lst):
      self.n = len(lst)
      self.t = [float('inf')] * self.n + lst
      for i in range(self.n - 1, 0, -1):                 # include root
          self.t[i] = min(self.t[i<<1], self.t[(i<<1)+1])

  def update(self, i, x):
      i += self.n
      self.t[i] = x
      while i > 1:
          self.t[i>>1] = min(self.t[i], self.t[i^1])     # min, not +
          i >>= 1

  def query(self, lo, hi):
      ans = float('inf')                                  # min identity
      lo += self.n; hi += self.n
      while lo < hi:
          if lo & 1: ans = min(ans, self.t[lo]); lo += 1
          if hi & 1: hi -= 1; ans = min(ans, self.t[hi])
          lo >>= 1; hi >>= 1
      return ans
fw = Fenwick([999,2,1,999,999,999,999])
i = fw.query(0, 3)
print(i)
1
The code you provided is actually a *Segment Tree*, not a Fenwick Tree. It works by using a compact array representation of a complete binary tree to perform range minimum queries.

,*** 1. Structure
-   *Array Layout:* For an input list of size $n$, it creates an array =t= of size $2n$.
    ,*   Indices =n= to =2n-1= store the original elements (leaves).
    ,*   Indices =1= to =n-1= store the minimum of their children (internal nodes).
-   *Parent-Child Logic:* For any node at index =i=:
    ,*   Left child: =i << 1= (or =2i=)
    ,*   Right child: =(i << 1) + 1= (or =2i + 1=)
    ,*   Parent: =i >> 1= (or =i // 2=)

,*** 2. Why it works

,**** Initialization (=__init__=)
It populates the leaves first, then iterates backwards from =n-1= down to =1=. This ensures that when calculating the minimum for node =i=, its children (=2i= and =2i+1=) have already been processed (or are leaves).

,**** Point Update (=update=)
1.  Updates the leaf at =i + n=.
2.  Moves up the tree (=i >>= 1=), re-calculating the minimum of the current node by comparing the updated node with its sibling (=i ^ 1=). This propagates the change up to the root in $O(\log n)$ time.

,**** Range Query (=query=)
This uses a "bottom-up" approach on the interval =[lo, hi)=:
1.  If =lo= is a right child (=lo & 1=), it's the only child of its parent inside the range. We include it in the minimum and move to the next subtree (=lo += 1=).
2.  If =hi= is a right child, the element at =hi-1= is inside the range. We include it and move left.
3.  We then move both pointers to their parents (=>> 1=).
4.  This collects only the "minimal" set of nodes covering the range in $O(\log n)$ time.

,*** Summary
While a *Fenwick Tree* (Binary Indexed Tree) is usually used for prefix sums and handles point updates in $O(\log n)$, it cannot efficiently perform range *minimum* queries for arbitrary ranges. This *Segment Tree* does exactly that by explicitly storing the minimum of power-of-two blocks.

,***