4.8 KiB
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.
,***