Implementation of Persistent segment trees in Python

Below is the complete implementation of a Persistent Segment Tree in Python:

Python
class Node:
    def __init__(self, value=0, left=None, right=None):

        # Initialize a new node
        self.value = value  # The value stored in this node
        self.left = left    # Reference to the left child node
        self.right = right  # Reference to the right child node


def build(arr, left, right):

    # Function to build the initial segment tree
    if left == right:

        # If the current segment is a single element, create a leaf node
        return Node(value=arr[left])

    # Calculate the mid-point of the current segment
    mid = (left + right) // 2

    # Recursively build the left and right subtrees
    left_child = build(arr, left, mid)
    right_child = build(arr, mid + 1, right)

    # Create a new node with the sum of values of left and right children
    return Node(value=left_child.value + right_child.value, left=left_child, right=right_child)


def update(prev_node, left, right, idx, new_value):

    # Function to perform an update operation on the segment tree persistently
    if left == right:

        # If the current segment is a single element, create a new node with the updated value
        return Node(value=new_value)

    # Calculate the mid-point of the current segment
    mid = (left + right) // 2

    # Determine whether the index to be updated lies in the left or right subtree
    if idx <= mid:

        # Recursively update the left subtree, keep the right subtree unchanged
        left_child = update(prev_node.left, left, mid, idx, new_value)
        right_child = prev_node.right
    else:

        # Recursively update the right subtree, keep the left subtree unchanged
        left_child = prev_node.left
        right_child = update(prev_node.right, mid + 1, right, idx, new_value)

    # Create a new node with the sum of values of the updated left and right children
    return Node(value=left_child.value + right_child.value, left=left_child, right=right_child)


def query(node, left, right, query_left, query_right):

    # Function to perform a range query on the segment tree
    if query_left > right or query_right < left:
        # If the query range does not overlap with the current segment, return 0
        return 0

    if query_left <= left and right <= query_right:

        # If the current segment is completely within the query range, return the value of the current node
        return node.value

    # Calculate the mid-point of the current segment
    mid = (left + right) // 2

    # Recursively query the left and right subtrees and return the sum of results
    return query(node.left, left, mid, query_left, query_right) + query(node.right, mid + 1, right, query_left, query_right)


# Example usage
if __name__ == "__main__":

    # Initial array
    arr = [1, 2, 3, 4, 5]

    # Build the initial segment tree
    root = build(arr, 0, len(arr) - 1)

    # Create a new version with an update (change the value at index 2 to 10)
    new_root = update(root, 0, len(arr) - 1, 2, 10)

    # Query the original and new versions
    print(query(root, 0, len(arr) - 1, 1, 3))      # Output: 9 (2+3+4)
    print(query(new_root, 0, len(arr) - 1, 1, 3))  # Output: 16 (2+10+4)

Output
9
16

Persistent Segment Tree in Python

Persistent data structures are a powerful tool in computer science, enabling us to maintain and access multiple versions of a data structure over time. One such structure is the Persistent Segment Tree. Segment trees are versatile data structures that allow efficient querying and updating of array intervals. By making a segment tree persistent, we enhance its capability to maintain historical versions, which is particularly useful in competitive programming and real-time applications where rollback and point-in-time queries are needed. This article explores the concept, implementation in Python.

Persistent segment trees

Similar Reads

What is Persistent Segment Tree?

Persistence in data structures refers to the ability to maintain access to previous versions of the data structure even after modifications. This can be achieved using techniques such as path copying, where only the parts of the structure that need to be changed are copied, thus saving space and time....

Representation of Persistent Segment Tree:

Each node in a Persistent Segment Tree contains:...

Persistent Segment Tree Operations

Persistent Segment Trees allow you to perform updates and queries efficiently while preserving the history of changes. Here are the primary operations you can perform on a Persistent Segment Tree:...

Illustration of working of Persistent Segment Tree in Python:

Let’s walk through a detailed example step-by-step to illustrate how the persistent segment tree works:...

Implementation of Persistent segment trees in Python

Below is the complete implementation of a Persistent Segment Tree in Python:...

Complexity Analysis of Persistent Segment Tree:

OperationTime ComplexitySpace Complexity (per update)DescriptionBuildO(n log n)O(n log n)Construct the initial segment tree from an array of size nUpdateO(log n)O(log n)Create a new version of the tree with an updated value at a specific indexQueryO(log n)O(1)Perform a range query on any version of the tree...

Contact Us