


'''simple docstring'''
from collections.abc import Sequence
from queue import Queue




class        _UpperCamelCase	:


				'''simple docstring'''


				def __init__(     self							,      a_							,      a_							,      a_							,      a_=None							,      a_=None							)    ->  str:
					lowercase						:		Tuple   					=		start
					lowercase						:		str   					=		end
					lowercase						:		Optional[int]   					=		val
					lowercase						:		List[str]   					=		(start + end) // 2
					lowercase						:		Tuple   					=		left
					lowercase						:		List[str]   					=		right


				def __repr__(     self							)    ->  Optional[Any]:
					return F'''SegmentTreeNode(start={self.start}, end={self.end}, val={self.val})'''




class        _UpperCamelCase	:


				'''simple docstring'''


				def __init__(     self							,      a_							,      a_							)    ->  Tuple:
					lowercase						:		List[Any]   					=		collection
					lowercase						:		Optional[int]   					=		function
					if self.collection:
						lowercase						:		Optional[int]   					=		self._build_tree(0							,      len(snake_case__							) - 1							)

				def 	a__		(     self							,      a_							,      a_							)    ->  Optional[Any]:
					self._update_tree(self.root							,      snake_case__							,      snake_case__							)

				def 	a__		(     self							,      a_							,      a_							)    ->  int:
					return self._query_range(self.root							,      snake_case__							,      snake_case__							)

				def 	a__		(     self							,      a_							,      a_							)    ->  List[str]:
					if start == end:
						return SegmentTreeNode(snake_case__							,      snake_case__							,      self.collection[start]							)
					lowercase						:		List[str]   					=		(start + end) // 2
					lowercase						:		Optional[Any]   					=		self._build_tree(snake_case__							,      snake_case__							)
					lowercase						:		str   					=		self._build_tree(mid + 1							,      snake_case__							)
					return SegmentTreeNode(snake_case__							,      snake_case__							,      self.fn(left.val							,      right.val							)							,      snake_case__							,      snake_case__							)

				def 	a__		(     self							,      a_							,      a_							,      a_							)    ->  int:
					if node.start == i and node.end == i:
						lowercase						:		int   					=		val
						return
					if i <= node.mid:
						self._update_tree(node.left							,      snake_case__							,      snake_case__							)
					else:
						self._update_tree(node.right							,      snake_case__							,      snake_case__							)
					lowercase						:		Optional[int]   					=		self.fn(node.left.val							,      node.right.val							)

				def 	a__		(     self							,      a_							,      a_							,      a_							)    ->  Any:
					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							,      snake_case__							,      snake_case__							)
						else:
							# range in left child tree and right child tree
							return self.fn(
							    self._query_range(node.left							,      snake_case__							,      node.mid							)							,      self._query_range(node.right							,      node.mid + 1							,      snake_case__							)							,      )
					else:
						# range in right child tree
						return self._query_range(node.right							,      snake_case__							,      snake_case__							)


				def 	a__		(     self							)    ->  Union[str, Any]:
					if self.root is not None:
						lowercase						:		Optional[int]   					=		Queue()
						queue.put(self.root							)
						while not queue.empty():
							lowercase						:		str   					=		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("""*""" * 5_0)
										lowerCAmelCase   : Dict             =				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()










"""simple docstring"""



from __future__ import annotations

from collections.abc import Iterator
from typing import Any




class 			lowerCAmelCase__			:
   def __init__(		self      :	Any							,			snake_case__      :	Any							):


        '''simple docstring'''
        UpperCAmelCase__						:    Any							=							data
        UpperCAmelCase__						:    Node | None							=							None




class 			lowerCAmelCase__			:
   def __init__(		self      :	Dict							):


        '''simple docstring'''
        UpperCAmelCase__						:    Tuple							=							None
        UpperCAmelCase__						:    Optional[int]							=							None
   def __iter__(		self      :	Tuple							):


        '''simple docstring'''
        UpperCAmelCase__						:    Optional[int]							=							self.head
        while self.head:
             yield node.data
             UpperCAmelCase__						:    Optional[Any]							=							node.next
             if node == self.head:
                  break
   def __len__(		self      :	Tuple							):


        '''simple docstring'''
        return sum(1 for _ in self							)
   def __repr__(		self      :	str							):


        '''simple docstring'''
        return "->".join(str(snake_case__							) for item in iter(self							)							)
   def       __a							(		self      :	Optional[Any]							,			snake_case__      :	Any							):


        '''simple docstring'''
        self.insert_nth(len(self							)							,			snake_case__							)
   def       __a							(		self      :	Optional[Any]							,			snake_case__      :	Any							):


        '''simple docstring'''
        self.insert_nth(0							,			snake_case__							)
   def       __a							(		self      :	Any							,			snake_case__      :	int							,			snake_case__      :	Any							):


        '''simple docstring'''
        if index < 0 or index > len(self							):
             raise IndexError("list index out of range."							)
        UpperCAmelCase__						:    Any							=							Node(snake_case__							)
        if self.head is None:
             UpperCAmelCase__						:    Union[str, Any]							=							new_node  # first node points itself
             UpperCAmelCase__						:    List[str]							=							new_node
        elif index == 0:  # insert at head
             UpperCAmelCase__						:    Optional[Any]							=							self.head
             UpperCAmelCase__						:    List[Any]							=							new_node
        else:
             UpperCAmelCase__						:    Union[str, Any]							=							self.head
             for _ in range(index - 1							):
                  UpperCAmelCase__						:    Dict							=							temp.next
             UpperCAmelCase__						:    Tuple							=							temp.next
             UpperCAmelCase__						:    str							=							new_node
             if index == len(self							) - 1:  # insert at tail
                  UpperCAmelCase__						:    Union[str, Any]							=							new_node
   def       __a							(		self      :	List[Any]							):


        '''simple docstring'''
        return self.delete_nth(0							)
   def       __a							(		self      :	Optional[Any]							):


        '''simple docstring'''
        return self.delete_nth(len(self							) - 1							)
   def       __a							(		self      :	Tuple							,			snake_case__      :	int = 0							):


        '''simple docstring'''
        if not 0 <= index < len(self							):
             raise IndexError("list index out of range."							)
        UpperCAmelCase__						:    Union[str, Any]							=							self.head
        if self.head == self.tail:  # just one node
             UpperCAmelCase__						:    str							=							None
        elif index == 0:  # delete head node
             UpperCAmelCase__						:    List[Any]							=							self.tail.next.next
             UpperCAmelCase__						:    Dict							=							self.head.next
        else:
             UpperCAmelCase__						:    List[Any]							=							self.head
             for _ in range(index - 1							):
                  UpperCAmelCase__						:    Tuple							=							temp.next
             UpperCAmelCase__						:    Dict							=							temp.next
             UpperCAmelCase__						:    Dict							=							temp.next.next
             if index == len(self							) - 1:  # delete at tail
                  UpperCAmelCase__						:    int							=							temp
        return delete_node.data




   def       __a							(		self      :	Any							):


        '''simple docstring'''
        return len(self							) == 0




def 	SCREAMING_SNAKE_CASE__       (  )->		None:






     '''simple docstring'''



     UpperCAmelCase__						:    str							=							CircularLinkedList()
     assert len(snake_case				) == 0
     assert circular_linked_list.is_empty() is True
     assert str(snake_case				) == ""

     try:
          circular_linked_list.delete_front()
          raise AssertionError  # This should not happen
     except IndexError:
          assert True  # This should happen

     try:
          circular_linked_list.delete_tail()
          raise AssertionError  # This should not happen
     except IndexError:
          assert True  # This should happen

     try:
          circular_linked_list.delete_nth(-1				)
          raise AssertionError
     except IndexError:
          assert True

     try:
          circular_linked_list.delete_nth(0				)
          raise AssertionError
     except IndexError:
          assert True

     assert circular_linked_list.is_empty() is True
     for i in range(5				):
          assert len(snake_case				) == i
          circular_linked_list.insert_nth(snake_case			,					i + 1				)
     assert str(snake_case				) == "->".join(str(snake_case				) for i in range(1			,					6				)				)

     circular_linked_list.insert_tail(6				)
     assert str(snake_case				) == "->".join(str(snake_case				) for i in range(1			,					7				)				)
     circular_linked_list.insert_head(0				)
     assert str(snake_case				) == "->".join(str(snake_case				) for i in range(0			,					7				)				)

     assert circular_linked_list.delete_front() == 0
     assert circular_linked_list.delete_tail() == 6
     assert str(snake_case				) == "->".join(str(snake_case				) for i in range(1			,					6				)				)
     assert circular_linked_list.delete_nth(2				) == 3

     circular_linked_list.insert_nth(2			,					3				)
     assert str(snake_case				) == "->".join(str(snake_case				) for i in range(1			,					6				)				)

     assert circular_linked_list.is_empty() is False


if __name__ == "__main__":
 import doctest

 doctest.testmod()


