Segment tree
Segment Tree
InductiveSegment tree#✓fully proved
A segment tree with values in \(\alpha\) is either empty, a leaf holding a value in \(\alpha\), or an internal node holding a cached segment aggregate in \(\alpha\), a cached segment length in \(\mathbb{N}\), a left child and a right child, both segment trees.
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
Used by 19
DefinitionAggregate of a segment tree#✓fully proved
The aggregate of a segment tree with values in an additive monoid is \(0\) for the empty tree, \(x\) for a single leaf with value \(x\), and the aggregate cached at the root for an internal node.
def agg {α : Type u} [AddMonoid α] : SegmentTree α → α
| .empty => 0
| .leaf x => x
| .node cached _ _ _ => cached
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 1 · Used by 14
DefinitionSize of a segment tree#✓fully proved
The size of a segment tree is \(0\) for the empty tree, \(1\) for a leaf, and, for an internal node, the segment length cached at that node.
When every cached length is the sum of the sizes of the node's children, this is the number of leaves, and internal nodes answer in constant time.
def size {α : Type u} : SegmentTree α → Nat
| .empty => 0
| .leaf _ => 1
| .node _ cachedSize _ _ => cachedSize
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 1 · Used by 15
DefinitionAccumulator traversal of a segment tree#✓fully proved
Given a segment tree and a list \(acc\), the accumulator traversal returns \(acc\) for the empty tree, the list \(acc\) with \(x\) prepended for a leaf with value \(x\), and, for an internal node with left child \(L\) and right child \(R\), the traversal of \(L\) starting from the result of the traversal of \(R\) starting from \(acc\).
Threading the output suffix this way collects the leaves of an \(n\)-leaf tree in linear time instead of repeatedly appending (and copying) left-subtree results.
def toListAux {α : Type u} : SegmentTree α → List α → List α
| .empty, acc => acc
| .leaf x, acc => x :: acc
| .node _ _ left right, acc => left.toListAux (right.toListAux acc)
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 1 · Used by 3
DefinitionLeaf list of a segment tree#✓fully proved
The leaf list of a segment tree is the list of its leaf values from left to right: the empty list for the empty tree, \([x]\) for a leaf with value \(x\), and the leaf list of the left child followed by the leaf list of the right child for an internal node.
def toList {α : Type u} (t : SegmentTree α) : List α :=
t.toListAux []
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 2 · Used by 15
TheoremAccumulator traversal prepends the leaf list#✓fully proved
For every segment tree \(t\) and every list \(acc\), the accumulator traversal of \(t\) starting from \(acc\) returns the leaf list of \(t\) followed by \(acc\).
@[simp]
theorem toListAux_eq {α : Type u} (t : SegmentTree α) (acc : List α) :
t.toListAux acc = t.toList ++ acc
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 3 · Used by 1
TheoremLeaf list of an internal node#✓fully proved
For every internal node of a segment tree, with any cached aggregate, any cached length, left child \(L\) and right child \(R\), its leaf list is the leaf list of \(L\) followed by the leaf list of \(R\).
With the accumulator definition of the leaf list this is a theorem, not a definitional unfolding.
@[simp]
theorem toList_node {α : Type u} (agg : α) (sz : Nat) (left right : SegmentTree α) :
(SegmentTree.node agg sz left right).toList = left.toList ++ right.toList
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 4 · Used by 7
InductiveValid segment trees#✓fully proved
Validity of a segment tree over an additive monoid is defined inductively: the empty tree and every leaf are valid, and an internal node with valid left child \(L\) and valid right child \(R\) is valid when its cached aggregate is the aggregate of \(L\) plus the aggregate of \(R\) and its cached length is the size of \(L\) plus the size of \(R\). Here the aggregate and size of the empty tree are \(0\) and \(0\), of a leaf with value \(x\) are \(x\) and \(1\), and of an internal node are its cached aggregate and cached length.
inductive Valid {α : Type u} [AddMonoid α] : SegmentTree α → Prop where
| empty : Valid .empty
| leaf (x : α) : Valid (.leaf x)
| node {left right : SegmentTree α} (hLeft : Valid left)
(hRight : Valid right) :
Valid (.node (left.agg + right.agg) (left.size + right.size) left right)
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 3 · Used by 8
TheoremSize of a valid segment tree#✓fully proved
If \(t\) is a valid segment tree with values in an additive monoid, then the length of the list of leaf values of \(t\), read from left to right, equals the size of \(t\).
theorem length_toList_of_valid {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) : t.toList.length = t.size
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 6 · Used by 3
TheoremAggregate of a valid segment tree#✓fully proved
If \(t\) is a valid segment tree with values in an additive monoid, then the aggregate of \(t\) equals the sum of the leaf values of \(t\), taken from left to right.
theorem agg_eq_sum_toList {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) : t.agg = t.toList.sum
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 6 · Used by 3
DefinitionBuilding a segment tree from a list#✓fully proved
The segment tree built from a list \(L\) with entries in an additive monoid is the empty tree if \(L\) is empty, and a single leaf with value \(x\) if \(L = (x)\). If \(L\) has length \(n \ge 2\), it is the internal node whose left child is the tree built from the first \(\lfloor n/2 \rfloor\) entries of \(L\), whose right child is the tree built from the remaining entries, and which caches the aggregate of the left child plus the aggregate of the right child, in that order, and the sum of the sizes of its children.
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 3 · Used by 8
TheoremBuilt segment trees are valid#✓fully proved
For every list \(xs\) over an additive monoid, the segment tree built from \(xs\) is valid.
theorem valid_build {α : Type u} [AddMonoid α] (xs : List α) :
(build xs).Valid
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
Uses 7 · Used by 6
TheoremBuilding a segment tree preserves the list#✓fully proved
For every list \(xs\) with entries in an additive monoid, the leaf list of the segment tree built from \(xs\) is \(xs\).
@[simp]
theorem toList_build {α : Type u} [AddMonoid α] (xs : List α) :
(build xs).toList = xs
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
Uses 7 · Used by 4
TheoremSize of a built segment tree#✓fully proved
For every list \(xs\) with entries in an additive monoid, the segment tree built from \(xs\) has size equal to the length of \(xs\).
@[simp]
theorem size_build {α : Type u} [AddMonoid α] (xs : List α) :
(build xs).size = xs.length
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
Uses 6 · Used by 1
TheoremAggregate of a built segment tree#✓fully proved
For every list \(L\) with entries in an additive monoid, the aggregate of the segment tree built from \(L\) equals the sum of the entries of \(L\), taken from left to right.
theorem agg_build {α : Type u} [AddMonoid α] (xs : List α) :
(build xs).agg = xs.sum
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
DefinitionRange query on a segment tree#✓fully proved
For a segment tree \(t\) with values in an additive monoid and natural numbers \(l, r\), the range query over \([l, r)\), with positions counted from the start of the segment of \(t\), is defined recursively. On the empty tree it is \(0\). On a leaf with value \(x\) it is \(x\) if \(l = 0 < r\), and \(0\) otherwise. On an internal node with cached aggregate \(a\), cached size \(s\) and children \(t_1, t_2\), it is \(0\) if \(r \le l\) or \(s \le l\); otherwise it is \(a\) if \(l = 0\) and \(s \le r\); and in all remaining cases it is the query over \([l, r)\) on \(t_1\) plus the query over \([l - m, r - m)\) on \(t_2\), where \(m\) is the size of \(t_1\) and subtraction is truncated at \(0\).
An empty range and a node disjoint from the range contribute \(0\) without descending, and a fully covered node contributes its cached aggregate.
def query {α : Type u} [AddMonoid α] : SegmentTree α → Nat → Nat → α
| .empty, _, _ => 0
| .leaf x, l, r => if l = 0 ∧ 0 < r then x else 0
| .node cached segmentSize left right, l, r =>
if r ≤ l then 0
else if segmentSize ≤ l then 0
else if l = 0 ∧ segmentSize ≤ r then cached
else query left l r + query right (l - left.size) (r - left.size)
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 2 · Used by 3
TheoremCorrectness of range queries on a valid segment tree#✓fully proved
Let \(t\) be a valid segment tree with values in an additive monoid, let \((x_0, \dots, x_{n-1})\) be its leaf values from left to right, and let \(l, r\) be natural numbers. The range query over \([l, r)\) on \(t\) returns \(\sum_{l \le k < \min(r, n)} x_k\), the sum taken in increasing order of \(k\); it is \(0\) when \(\min(r, n) \le l\).
theorem query_eq {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) (l r : Nat) :
t.query l r = ((t.toList.drop l).take (r - l)).sum
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 9 · Used by 2
TheoremRange queries on a built segment tree#✓fully proved
Let \(L = (x_0, \dots, x_{n-1})\) be a list with entries in an additive monoid and let \(l, r\) be natural numbers. The range query over \([l, r)\) on the segment tree built from \(L\) returns \(\sum_{l \le k < \min(r, n)} x_k\), the sum taken in increasing order of \(k\); it is \(0\) when \(\min(r, n) \le l\).
theorem query_build {α : Type u} [AddMonoid α] (xs : List α) (l r : Nat) :
(build xs).query l r = ((xs.drop l).take (r - l)).sum
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
DefinitionPoint update of a segment tree#✓fully proved
The point update of a segment tree over an additive monoid at an index \(i \in \mathbb{N}\), relative to the tree's segment, with a value \(y\) is defined recursively. The empty tree stays empty. A leaf becomes a leaf with value \(y\) if \(i = 0\) and is unchanged otherwise. At an internal node with left child \(L\) and right child \(R\): if \(i\) is less than the size of \(L\), then \(L\) is replaced by its point update at \(i\) with \(y\), and otherwise \(R\) is replaced by its point update at \(i\) minus the size of \(L\) with \(y\); the node keeps its cached length, and its cached aggregate becomes the aggregate of the new left child plus the aggregate of the new right child.
def update {α : Type u} [AddMonoid α] : SegmentTree α → Nat → α → SegmentTree α
| .empty, _, _ => .empty
| .leaf x, i, y => if i = 0 then .leaf y else .leaf x
| .node _ segmentSize left right, i, y =>
if i < left.size then
let left' := left.update i y
.node (left'.agg + right.agg) segmentSize left' right
else
let right' := right.update (i - left.size) y
.node (left.agg + right'.agg) segmentSize left right'
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 3 · Used by 7
TheoremPoint update preserves the size of a segment tree#✓fully proved
For every segment tree \(t\) over an additive monoid, every index \(i\) and every value \(y\), the point update of \(t\) at \(i\) with \(y\) has the same size as \(t\).
Every node on the update path keeps its cached segment length.
@[simp]
theorem size_update {α : Type u} [AddMonoid α] (t : SegmentTree α)
(i : Nat) (y : α) : (t.update i y).size = t.size
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 4 · Used by 1
TheoremPoint update preserves validity#✓fully proved
If \(t\) is a valid segment tree over an additive monoid, then for every natural number \(i\) and every value \(y\), the point update of \(t\) at \(i\) with \(y\) is valid.
theorem Valid.update {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) (i : Nat) (y : α) : (t.update i y).Valid
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 6 · Used by 2
TheoremLeaf list after an in-range point update#✓fully proved
Let \(t\) be a valid segment tree over an additive monoid and let \(i\) be a natural number less than the size of \(t\). Then for every value \(y\), the leaf list of the point update of \(t\) at \(i\) with \(y\) is the leaf list of \(t\) with its entry at position \(i\) (counting from \(0\)) replaced by \(y\).
Validity is what ties the cached sizes used for routing to the leaf list.
theorem toList_update_of_lt {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) {i : Nat} (hi : i < t.size) (y : α) :
(t.update i y).toList = t.toList.set i y
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 8 · Used by 1
TheoremOut-of-range point update leaves the leaf list unchanged#✓fully proved
For every valid segment tree \(t\) over an additive monoid, every index \(i\) at least the size of \(t\) and every value \(y\), the point update of \(t\) at \(i\) with \(y\) has the same leaf list as \(t\).
theorem toList_update_of_le {α : Type u} [AddMonoid α] {t : SegmentTree α}
(h : t.Valid) {i : Nat} (hi : t.size ≤ i) (y : α) :
(t.update i y).toList = t.toList
inductive SegmentTree (α : Type u) where
| empty : SegmentTree α
| leaf : α → SegmentTree α
| node : α → Nat → SegmentTree α → SegmentTree α → SegmentTree α
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:42
Uses 7
TheoremPoint update of a built segment tree#✓fully proved
For every list \(xs\) with entries in an additive monoid, every index \(i\) smaller than the length of \(xs\) and every value \(y\), the leaf list of the segment tree built from \(xs\), after the point update at \(i\) with \(y\), is \(xs\) with its entry at position \(i\) (counting from \(0\)) replaced by \(y\).
theorem toList_update_build {α : Type u} [AddMonoid α] {xs : List α}
{i : Nat} (hi : i < xs.length) (y : α) :
((build xs).update i y).toList = xs.set i y
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
Uses 8 · Used by 2
TheoremAggregate after a point update of a built segment tree#✓fully proved
Let \(L = (x_0, \dots, x_{n-1})\) be a list with entries in an additive monoid, let \(i < n\), and let \(y\) be an element of the monoid. Applying the point update at index \(i\) with value \(y\) to the segment tree built from \(L\) gives a tree whose aggregate is the sum, taken from left to right, of the list obtained from \(L\) by replacing \(x_i\) with \(y\).
theorem agg_update_build {α : Type u} [AddMonoid α] {xs : List α}
{i : Nat} (hi : i < xs.length) (y : α) :
((build xs).update i y).agg = (xs.set i y).sum
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
TheoremRange queries after a point update of a built segment tree#✓fully proved
Let \(L = (x_0, \dots, x_{n-1})\) be a list with entries in an additive monoid, let \(i < n\), let \(y\) be an element of the monoid, and let \(L'\) be the list obtained from \(L\) by replacing \(x_i\) with \(y\), with entries \(x'_0, \dots, x'_{n-1}\). Apply the point update at index \(i\) with value \(y\) to the segment tree built from \(L\). For all natural numbers \(l, r\), the range query over \([l, r)\) on the result returns \(\sum_{l \le k < \min(r, n)} x'_k\), the sum taken in increasing order of \(k\); it is \(0\) when \(\min(r, n) \le l\).
theorem query_update_build {α : Type u} [AddMonoid α] {xs : List α}
{i : Nat} (hi : i < xs.length) (y : α) (l r : Nat) :
((build xs).update i y).query l r =
(((xs.set i y).drop l).take (r - l)).sum
def build {α : Type u} [AddMonoid α] : List α → SegmentTree α
| [] => .empty
| [x] => .leaf x
| xs@(_ :: _ :: _) =>
let left := build (xs.take (xs.length / 2))
let right := build (xs.drop (xs.length / 2))
.node (left.agg + right.agg) (left.size + right.size) left right
termination_by xs => xs.length
decreasing_by
all_goals
simp_all only [List.length_take, List.length_drop, List.length_cons]
omega
CSLibExt/Algorithms/Lean/DataStructures/SegmentTree.lean:139
Uses 8
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.