Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0457860
Suffix Array and LCP Array Implementation
putul03 Oct 19, 2024
465cea3
Delete divide_and_conquer/suffix_array_lcp.py
putul03 Oct 19, 2024
8ab2927
Add files via upload
putul03 Oct 19, 2024
f5d380a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
819fdc8
Update persistent_segment_tree.py
putul03 Oct 19, 2024
5de6184
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
82270b7
Update persistent_segment_tree.py
putul03 Oct 19, 2024
ff5a9b8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
04b44c4
Update persistent_segment_tree.py
putul03 Oct 19, 2024
0f5718f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
eb9e2b7
Update persistent_segment_tree.py
putul03 Oct 19, 2024
5c605df
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
55e6a87
Update persistent_segment_tree.py
putul03 Oct 19, 2024
eaafd1c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
124b177
Update persistent_segment_tree.py
putul03 Oct 19, 2024
902ed93
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
f64233a
Update persistent_segment_tree.py
putul03 Oct 19, 2024
4484382
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
210e9a2
Update persistent_segment_tree.py
putul03 Oct 19, 2024
fc627f1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
4598bc8
Update persistent_segment_tree.py
putul03 Oct 19, 2024
103651e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
e968d12
Update persistent_segment_tree.py
putul03 Oct 19, 2024
4e95c90
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
9e07fc9
Update persistent_segment_tree.py
putul03 Oct 19, 2024
bcd9f5d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 19, 2024
6ff786b
Refactor Node class to use dataclass
cclauss Sep 23, 2026
2f96e3f
Merge branch 'master' into Putul01
cclauss Sep 23, 2026
d42398b
updating DIRECTORY.md
cclauss Sep 23, 2026
8372618
Refactor PersistentSegmentTree implementation
cclauss Sep 23, 2026
2bd9625
Refactor Node initialization and update methods
cclauss Sep 23, 2026
c69a531
Apply suggestion from @cclauss
cclauss Sep 23, 2026
5696129
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 23, 2026
48626c8
Update persistent_segment_tree.py
cclauss Sep 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
* [Mirror Binary Tree](data_structures/binary_tree/mirror_binary_tree.py)
* [Non Recursive Segment Tree](data_structures/binary_tree/non_recursive_segment_tree.py)
* [Number Of Possible Binary Trees](data_structures/binary_tree/number_of_possible_binary_trees.py)
* [Persistent Segment Tree](data_structures/binary_tree/persistent_segment_tree.py)
* [Red Black Tree](data_structures/binary_tree/red_black_tree.py)
* [Segment Tree](data_structures/binary_tree/segment_tree.py)
* [Segment Tree Other](data_structures/binary_tree/segment_tree_other.py)
Expand Down
138 changes: 138 additions & 0 deletions data_structures/binary_tree/persistent_segment_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from __future__ import annotations

from dataclasses import dataclass


@dataclass
class Node:
value: int
left: Node | None = None
right: Node | None = None


class PersistentSegmentTree:
def __init__(self, arr: list[int]) -> None:
self.n: int = len(arr)
self.roots: list[Node] = []
self.roots.append(self._build(arr, 0, self.n - 1))

def _build(self, arr: list[int], start: int, end: int) -> Node:
"""
Builds a segment tree from the provided array.

>>> pst = PersistentSegmentTree([1, 2, 3, 4])
>>> root = pst._build([1, 2, 3, 4], 0, 3)
>>> root.value # Sum of the whole array
10
>>> root.left.value # Sum of the left half
3
>>> root.right.value # Sum of the right half
7
"""
if start == end:
return Node(arr[start])
mid = (start + end) // 2
left = self._build(arr, start, mid)
right = self._build(arr, mid + 1, end)
return Node(value=left.value + right.value, left=left, right=right)

def update(self, version: int, index: int, value: int) -> int:
"""
Updates the value at the given index and returns the new version.

>>> pst = PersistentSegmentTree([1, 2, 3, 4])
>>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5
>>> pst.query(version_1, 0, 3) # Query sum of all elements in new version
13
>>> pst.query(0, 0, 3) # Original version remains unchanged
10
>>> version_2 = pst.update(version_1, 3, 6) # Update index 3 to 6 in version_1
>>> pst.query(version_2, 0, 3) # Query sum of all elements in newest version
15
"""
new_root = self._update(self.roots[version], 0, self.n - 1, index, value)
self.roots.append(new_root)
return len(self.roots) - 1

def _update(self, node: Node, start: int, end: int, index: int, value: int) -> Node:
"""
Update the node for the specified index and value and return the new node.

>>> pst = PersistentSegmentTree([1, 2, 3, 4])
>>> old_root = pst.roots[0]
>>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5
>>> new_root.value # New sum after update
13
>>> old_root.value # Old root remains unchanged
10
>>> new_root.left.value # Updated left child
6
>>> new_root.right.value # Right child remains the same
7
"""
if start == end:
return Node(value)

mid = (start + end) // 2
new_node = Node(0)

if index <= mid:
new_node.left = self._update(node.left, start, mid, index, value)
new_node.right = node.right # Ensure right node is the same as the original
else:
new_node.left = node.left # Ensure left node is the same as the original
new_node.right = self._update(node.right, mid + 1, end, index, value)

new_node.value = new_node.left.value + (
new_node.right.value if new_node.right else 0
)

return new_node

def query(self, version: int, left: int, right: int) -> int:
"""
Queries the sum in the given range for the specified version.

>>> pst = PersistentSegmentTree([1, 2, 3, 4])
>>> pst.query(0, 0, 3) # Sum of all elements in original version
10
>>> pst.query(0, 1, 2) # Sum of elements at index 1 and 2 in original version
5
>>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5
>>> pst.query(version_1, 0, 3) # Sum of all elements in new version
13
>>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2
8
"""
return self._query(self.roots[version], 0, self.n - 1, left, right)

def _query(self, node: Node, start: int, end: int, left: int, right: int) -> int:
"""
Queries the sum of values in the range [left, right] for the given node.

>>> pst = PersistentSegmentTree([1, 2, 3, 4])
>>> root = pst.roots[0]
>>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2
5
>>> pst._query(root, 0, 3, 0, 3) # Sum of all elements
10
>>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3
7
"""
if node is None or left > end or right < start:
return 0
if left <= start and right >= end:
return node.value
mid = (start + end) // 2
return self._query(node.left, start, mid, left, right) + self._query(
node.right, mid + 1, end, left, right
)


# Running the doctests
if __name__ == "__main__":
import doctest

print("Running doctests...")
result = doctest.testmod()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error occurred while parsing the file: data_structures/binary_tree/persistent_segment_tree.py

Traceback (most recent call last):
  File "/opt/render/project/src/algorithms_keeper/parser/python_parser.py", line 137, in parse
    runner = LintRunner(file.path, source)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
libcst._exceptions.ParserSyntaxError: Syntax Error @ 139:5.
parser error: error at 138:4: expected one of ., import

    result = doctest.testmod()
    ^

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error occurred while parsing the file: data_structures/binary_tree/persistent_segment_tree.py

Traceback (most recent call last):
  File "/opt/render/project/src/algorithms_keeper/parser/python_parser.py", line 137, in parse
    runner = LintRunner(file.path, source)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
libcst._exceptions.ParserSyntaxError: Syntax Error @ 139:5.
parser error: error at 138:4: expected one of ., import

    result = doctest.testmod()
    ^

print(f"Ran {result.attempted} tests, {result.failed} failed.")
Loading