#+title: Segment Tree * Segment #+begin_src python 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 #+end_src #+begin_src python :results output 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) #+end_src #+RESULTS: : [inf, inf, 1, 999, 1, 999, 999, 999, 2, 1, 999, 999, 999, 999] : 0 #+begin_src python :results output 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) #+end_src #+RESULTS: : 1 #+begin_src markdown 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. ,*** #+end_src