153 lines
4.8 KiB
Org Mode
153 lines
4.8 KiB
Org Mode
#+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
|