Advanced Data Structures — Segment Trees, Fenwick Trees, Disjoint Sets
659 words
3 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Advanced Data Structures — Segment Trees, Fenwick Trees, Disjoint Sets ## 🎯 Learning Objectives - Build and query segment trees in O(log n) - Implement Fenwick tree for prefix sums - Apply DSU with union by rank and path compression - Solve range query problems with these structures * * * ## 1. Segment Tree ### 1...

Advanced Data Structures — Segment Trees, Fenwick Trees, Disjoint Sets
🎯 Learning Objectives
- Build and query segment trees in O(log n)
- Implement Fenwick tree for prefix sums
- Apply DSU with union by rank and path compression
- Solve range query problems with these structures
1. Segment Tree
1.1 Structure
Binary tree storing aggregate information (sum, min, max) for array segments.
Array: [5, 3, 7, 9, 1, 6] Segment Tree (sum): Root = 31, children = [8, 23], etc.
(Diagram)
1.2 Query: Range Sum [1, 4]
- Start at root [0-5]
- [0-5] partially overlaps → go to children
- [0-2] partially overlaps → go to children
- [0-1] partially → return right child [1] = 3
- [2] = 7 (fully covered)
- [3-5] partially → go to child [3-4] = 10 (fully covered)
- Result: 3 + 7 + 10 = 20
1.3 Time Complexity
| Operation | Time |
|---|---|
| Build | O(n) |
| Query | O(log n) |
| Point update | O(log n) |
| Range update (lazy) | O(log n) |
2. Fenwick Tree (Binary Indexed Tree)
2.1 Key Idea
Each index i stores sum of range (i - LSB(i) + 1, i], where LSB(i) = i & (-i).
Fenwick tree for [5, 3, 7, 9, 1, 6]:
| Index | Value | LSB | Stores Range |
|---|---|---|---|
| 1 | 5 | 1 | [1,1] |
| 2 | 8 | 2 | [1,2] |
| 3 | 7 | 1 | [3,3] |
| 4 | 24 | 4 | [1,4] |
| 5 | 1 | 1 | [5,5] |
| 6 | 7 | 2 | [5,6] |
2.2 Query: Prefix Sum [1, 5]
- i=5: tree[5]=1, i=5-1=4
- i=4: tree[4]=24, i=4-4=0
- Result: 1 + 24 = 25 Update: Add v at position i: while i ≤ n: tree[i] += v; i += LSB(i)
3. Disjoint Set Union (DSU)
3.1 Path Compression + Union by Rank
pythonclass DSU: def __init__(self, n): self.parent = list(range(n)) self.rank = [0] * n def find(self, x): # Path compression if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def union(self, x, y): # Union by rank px, py = self.find(x), self.find(y) if px == py: return False if self.rank[px] < self.rank[py]: px, py = py, px self.parent[py] = px if self.rank[px] == self.rank[py]: self.rank[px] += 1 return True
3.2 Tracing
Union(1, 2), Union(2, 3):
- Initially: parent = [0,1,2,3], rank = [0,0,0,0]
- Union(1,2): find(1)=1, find(2)=2, rank same, parent[2]=1, rank[1]=1
- Union(2,3): find(2)→1, find(3)=3, rank[1]=1 > rank[3]=0, parent[3]=1 Complexity: O(α(n)) per operation (inverse Ackermann — practically constant)
4. Common Pitfalls
Pitfall: Fenwick Tree for Min/Max
The mistake: Using Fenwick tree for range minimum query (RMQ).
Correct approach: Fenwick tree only works for prefix-able operations (sum, xor). For RMQ, use segment tree or Sparse Table.
5. Key Concepts Reference
| Structure | Build | Query | Update | Memory |
|---|---|---|---|---|
| Segment Tree | O(n) | O(log n) | O(log n) | O(4n) |
| Fenwick Tree | O(n log n) | O(log n) | O(log n) | O(n) |
| DSU | O(n) | O(α(n)) | O(α(n)) | O(n) |
| Sparse Table | O(n log n) | O(1) | N/A | O(n log n) |
6. 📝 Practice Questions
Q1: Build a segment tree for [2, 4, 1, 5, 3] for range sum.Answer: Root (0-4): 15 Left (0-2): 7, Right (3-4): 8 (0-1): 6, (2): 1, (3): 5, (4): 3 (0): 2, (1): 4 Query [1, 3]: right child of (0-1)=4 + (2)=1 + (3)=5 = 10 Q2: Fenwick tree: prefix sum up to 6 for tree = [3, 7, 2, 12, 5, 9].Answer: tree indices: 1=3, 2=7, 3=2, 4=12, 5=5, 6=9. prefix(6)=tree[6]+tree[4]=9+12=21. Verify: array = [3, 4, 2, 3, 5, 4]? Wait, Fenwick stores differently. tree[2]=7 means arr[1]+arr[2]=7. Let me verify: if tree = [3,7,2,12,5,9], then prefix(6)=tree[6]+tree[4]=9+12=21. prefix(5)=tree[5]+tree[4]=5+12=17. Q3: DSU: find operation with path compression. Explain the effect.Answer: After find(x), every node on the path from x to the root has its parent set directly to the root. Future finds for these nodes are O(1). Without path compression, find could be O(n) for a chain. Combined with union by rank, the amortized time is O(α(n)) — practically constant even for n = 10^600.
7. 🔗 Cross-References
- Week 1 - Greedy: Scheduling with DSU
- Week 5 - Flow Applications: Min-cut via segment tree
- BSCS4020 (DSA): Basic data structures Join Discord PreviousRandomized AlgorithmsNextExact Algorithms