Add remaining flashcards and reference files (qn_01, segment_tree, ds, learning)

This commit is contained in:
2026-05-26 01:30:51 +08:00
parent fa64e776ca
commit f603236a48
10 changed files with 639 additions and 14 deletions
+77
View File
@@ -0,0 +1,77 @@
#+title: Bit Tree
* binary indexd tree
#+begin_src python :results output
class BinaryIndexedTree:
def __init__(self, n: int):
self.tree = [0] * (n + 1)
def update(self, i: int, delta: int) -> None:
"""Add delta to element at index i (0-based)."""
idx = i + 1
while idx < len(self.tree):
self.tree[idx] += delta
idx += idx & (-idx)
def query(self, i: int) -> int:
"""Return prefix sum from 0 to i (0-based)."""
idx = i + 1
s = 0
while idx > 0:
s += self.tree[idx]
idx -= idx & (-idx)
return s
def range_query(self, l: int, r: int) -> int:
"""Return sum from l to r (0-based, inclusive)."""
if l == 0:
return self.query(r)
return self.query(r) - self.query(l - 1)
#+end_src
- update(i, delta) — adds delta to index i in O(log n)
- query(i) — prefix sum [0..i] in O(log n)
- range_query(l, r) — sum [l..r] in O(log n)
* min bit tree
That's a min-Fenwick (prefix minimum). Unlike sum-Fenwick, updates are point-set (not add-delta), and increasing a value is expensive — you'd need a segment tree for that.
#+begin_src python
import math
class MinFenwick:
def __init__(self, n: int, inf: int = math.inf):
self.n = n
self.inf = inf
self.tree = [inf] * (n + 1)
self.arr = [inf] * n # track actual values for rebuild
def update(self, i: int, val: int) -> None:
"""Set element at index i to val (0-based)."""
self.arr[i] = val
idx = i + 1
while idx <= self.n:
# rebuild this node from its covered range
lo = idx - (idx & (-idx)) # 0-based: lo
hi = idx - 1 # 0-based: hi
self.tree[idx] = min(self.arr[j] for j in range(lo, hi + 1))
idx += idx & (-idx)
def query(self, i: int) -> int:
"""Return min from 0 to i (0-based, inclusive)."""
idx = i + 1
res = self.inf
while idx > 0:
res = min(res, self.tree[idx])
idx -= idx & (-idx)
return res
#+end_src
- update(i, val) — set index i to val, O(log n · span) where span is the size of the covered range
- query(i) — prefix min [0..i], O(log n)
Caveat: If you need to increase a value (removing a minimum from consideration), this rebuilds the range each time — worst case O(n). For full range-min with arbitrary increases/decreases, use a segment tree instead.
* why doesn't min work with BIT?
:PROPERTIES:
:ANKI_NOTE_TYPE: Basic
:END:
** Front
Why doesn't min work well with Fenwick/Bit trees? What property does addition have that min lacks?
** Back
#+begin_quote
Fenwick trees require an =invertible= operation (a group). Addition is invertible via subtraction: range_query(l,r) = prefix(r) - prefix(l-1). Min has no inverse — you can't "subtract out" the minimum of [0..l-1] from prefix(r) to get [l..r].
Additionally, min's =update= breaks on value increases. Decreasing a value works fine (like sum's decrease), but increasing a value means the old minimum might have been removed, and you'd need to scan all elements in the node's covered range to find the new minimum. This makes updates O(span) instead of O(log n).
Good Fenwick operations are associative, have an identity element, and are incrementally updateable: sum, xor, gcd. Min/max work for prefix queries only, not range queries.
#+end_quote