

"""simple docstring"""






from __future__ import annotations

from sys import maxsize
from typing import Generic, TypeVar

__lowerCamelCase										=		TypeVar("T")





def 	lowercase      (   __UpperCamelCase						) ->      int:
 return (position - 1) // 2





def 	lowercase      (   __UpperCamelCase						) ->      int:
 return (2 * position) + 1





def 	lowercase      (   __UpperCamelCase						) ->      int:
 return (2 * position) + 2
class        _lowercase					(     Generic[T]     ):







     def __init__(      self       ):
      __magic_name__     =      []
      __magic_name__     =      {}
      __magic_name__     =      0







     def __len__(      self       ):
      return self.elements







     def __repr__(      self       ):
      return str(self.heap       )







     def 	lowerCAmelCase__    (      self       ):
      # Check if the priority queue is empty
      return self.elements == 0







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      # Add an element with given priority to the queue
      self.heap.append((elem, weight)       )
      __magic_name__     =      self.elements
      self.elements += 1
      self._bubble_up(UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self       ):
      # Remove and return the element with lowest weight (highest priority)
      if self.elements > 1:
       self._swap_nodes(0 ,						self.elements - 1       )
      __magic_name__   ,						__magic_name__     =      self.heap.pop()
      del self.position_map[elem]
      self.elements -= 1
      if self.elements > 0:
       __magic_name__   ,						__magic_name__     =      self.heap[0]
       self._bubble_down(UpperCamelCase_       )
      return elem







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      # Update the weight of the given key
      __magic_name__     =      self.position_map[elem]
      __magic_name__     =      (elem, weight)
      if position > 0:
       __magic_name__     =      get_parent_position(UpperCamelCase_       )
       __magic_name__   ,						__magic_name__     =      self.heap[parent_position]
       if parent_weight > weight:
        self._bubble_up(UpperCamelCase_       )
       else:
        self._bubble_down(UpperCamelCase_       )
      else:
       self._bubble_down(UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_       ):
      # Place a node at the proper position (upward movement) [to be used internally
      # only]
      __magic_name__     =      self.position_map[elem]
      if curr_pos == 0:
       return None
      __magic_name__     =      get_parent_position(UpperCamelCase_       )
      __magic_name__   ,						__magic_name__     =      self.heap[curr_pos]
      __magic_name__   ,						__magic_name__     =      self.heap[parent_position]
      if parent_weight > weight:
       self._swap_nodes(UpperCamelCase_ ,						UpperCamelCase_       )
       return self._bubble_up(UpperCamelCase_       )
      return None







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_       ):
      # Place a node at the proper position (downward movement) [to be used
      # internally only]
      __magic_name__     =      self.position_map[elem]
      __magic_name__   ,						__magic_name__     =      self.heap[curr_pos]
      __magic_name__     =      get_child_left_position(UpperCamelCase_       )
      __magic_name__     =      get_child_right_position(UpperCamelCase_       )
      if child_left_position < self.elements and child_right_position < self.elements:
       __magic_name__   ,						__magic_name__     =      self.heap[child_left_position]
       __magic_name__   ,						__magic_name__     =      self.heap[child_right_position]
       if child_right_weight < child_left_weight and child_right_weight < weight:
        self._swap_nodes(UpperCamelCase_ ,						UpperCamelCase_       )
        return self._bubble_down(UpperCamelCase_       )
      if child_left_position < self.elements:
       __magic_name__   ,						__magic_name__     =      self.heap[child_left_position]
       if child_left_weight < weight:
        self._swap_nodes(UpperCamelCase_ ,						UpperCamelCase_       )
        return self._bubble_down(UpperCamelCase_       )
      else:
       return None
      if child_right_position < self.elements:
       __magic_name__   ,						__magic_name__     =      self.heap[child_right_position]
       if child_right_weight < weight:
        self._swap_nodes(UpperCamelCase_ ,						UpperCamelCase_       )
        return self._bubble_down(UpperCamelCase_       )
      return None







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      # Swap the nodes at the given positions
      __magic_name__     =      self.heap[nodea_pos][0]
      __magic_name__     =      self.heap[nodea_pos][0]
      __magic_name__   ,						__magic_name__     =      (
          self.heap[nodea_pos],
          self.heap[nodea_pos],
      )
      __magic_name__     =      nodea_pos
      __magic_name__     =      nodea_pos


class        _lowercase					(     Generic[T]     ):







     def __init__(      self       ):
      __magic_name__     =      {}
      __magic_name__     =      0







     def __repr__(      self       ):
      return str(self.connections       )







     def __len__(      self       ):
      return self.nodes







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_       ):
      # Add a node in the graph if it is not in the graph
      if node not in self.connections:
       __magic_name__     =      {}
       self.nodes += 1







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      # Add an edge between 2 nodes in the graph
      self.add_node(UpperCamelCase_       )
      self.add_node(UpperCamelCase_       )
      __magic_name__     =      weight
      __magic_name__     =      weight





def 	lowercase      (   __UpperCamelCase      ,   ) ->      tuple[dict[T, int], dict[T, T | None]]:
 __magic_name__     =      {node: maxsize for node in graph.connections}
 __magic_name__     =      {node: None for node in graph.connections}

 __magic_name__     =      MinPriorityQueue()
 for node, weight in dist.items():
  priority_queue.push(__UpperCamelCase      ,   __UpperCamelCase						)

 if priority_queue.is_empty():
  return dist, parent

 # initialization
 __magic_name__     =      priority_queue.extract_min()
 __magic_name__     =      0
 for neighbour in graph.connections[node]:
  if dist[neighbour] > dist[node] + graph.connections[node][neighbour]:
   __magic_name__     =      dist[node] + graph.connections[node][neighbour]
   priority_queue.update_key(__UpperCamelCase      ,   dist[neighbour]						)
   __magic_name__     =      node

    # running prim's algorithm
 while not priority_queue.is_empty():
  __magic_name__     =      priority_queue.extract_min()
  for neighbour in graph.connections[node]:
   if dist[neighbour] > dist[node] + graph.connections[node][neighbour]:
    __magic_name__     =      dist[node] + graph.connections[node][neighbour]
    priority_queue.update_key(__UpperCamelCase      ,   dist[neighbour]						)
    __magic_name__     =      node
 return dist, parent




"""simple docstring"""






from collections.abc import Sequence
from queue import Queue
class        _lowercase					:







     def __init__(      self ,						UpperCamelCase_ ,						UpperCamelCase_ ,						UpperCamelCase_ ,						UpperCamelCase_=None ,						UpperCamelCase_=None       ):
      __magic_name__     =      start
      __magic_name__     =      end
      __magic_name__     =      val
      __magic_name__     =      (start + end) // 2
      __magic_name__     =      left
      __magic_name__     =      right







     def __repr__(      self       ):
      return f'''SegmentTreeNode(start={self.start}, end={self.end}, val={self.val})'''


class        _lowercase					:







     def __init__(      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      __magic_name__     =      collection
      __magic_name__     =      function
      if self.collection:
       __magic_name__     =      self._build_tree(0 ,						len(UpperCamelCase_       ) - 1       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      self._update_tree(self.root ,						UpperCamelCase_ ,						UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      return self._query_range(self.root ,						UpperCamelCase_ ,						UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      if start == end:
       return SegmentTreeNode(UpperCamelCase_ ,						UpperCamelCase_ ,						self.collection[start]       )
      __magic_name__     =      (start + end) // 2
      __magic_name__     =      self._build_tree(UpperCamelCase_ ,						UpperCamelCase_       )
      __magic_name__     =      self._build_tree(mid + 1 ,						UpperCamelCase_       )
      return SegmentTreeNode(UpperCamelCase_ ,						UpperCamelCase_ ,						self.fn(left.val ,						right.val       ) ,						UpperCamelCase_ ,						UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      if node.start == i and node.end == i:
       __magic_name__     =      val
       return
      if i <= node.mid:
       self._update_tree(node.left ,						UpperCamelCase_ ,						UpperCamelCase_       )
      else:
       self._update_tree(node.right ,						UpperCamelCase_ ,						UpperCamelCase_       )
      __magic_name__     =      self.fn(node.left.val ,						node.right.val       )







     def 	lowerCAmelCase__    (      self ,						UpperCamelCase_ ,						UpperCamelCase_ ,						UpperCamelCase_       ):
      if node.start == i and node.end == j:
       return node.val

      if i <= node.mid:
       if j <= node.mid:
        # range in left child tree
        return self._query_range(node.left ,						UpperCamelCase_ ,						UpperCamelCase_       )
       else:
        # range in left child tree and right child tree
        return self.fn(
            self._query_range(node.left ,						UpperCamelCase_ ,						node.mid       ) ,						self._query_range(node.right ,						node.mid + 1 ,						UpperCamelCase_       ) ,						)
      else:
       # range in right child tree
       return self._query_range(node.right ,						UpperCamelCase_ ,						UpperCamelCase_       )







     def 	lowerCAmelCase__    (      self       ):
      if self.root is not None:
       __magic_name__     =      Queue()
       queue.put(self.root       )
       while not queue.empty():
        __magic_name__     =      queue.get()
        yield node

        if node.left is not None:
         queue.put(node.left       )

        if node.right is not None:
         queue.put(node.right       )


if __name__ == "__main__":
 import operator

 for fn in [operator.add, max, min]:
  print("*" * 50)
  __lowerCamelCase										=		SegmentTree([2, 1, 5, 3, 4], fn)
  for node in arr.traverse():
   print(node)
  print()

  arr.update(1, 5)
  for node in arr.traverse():
   print(node)
  print()

  print(arr.query_range(3, 4))  # 7
  print(arr.query_range(2, 2))  # 5
  print(arr.query_range(1, 3))  # 13
  print()

