
from __future__ import annotations

import math
import random
from typing import Any







class 				lowercase		:




							def __init__(				self):
												lowercase							=						[]
												lowercase							=						0
												lowercase							=						0




							def  A__      (				self):
												return self.head == self.tail




							def  A__      (				self   ,A__):
												self.data.append(A__)
												lowercase							=						self.tail + 1




							def  A__      (				self):
												lowercase							=						self.data[self.head]
												lowercase							=						self.head + 1
												return ret




							def  A__      (				self):
												return self.tail - self.head





							def  A__      (				self):
												print(self.data)
												print('''**************''')
												print(self.data[self.head : self.tail])







class 				lowercase		:




							def __init__(				self   ,A__):
												lowercase							=						data
												lowercase							=						None
												lowercase							=						None
												lowercase							=						1




							def  A__      (				self):
												return self.data




							def  A__      (				self):
												return self.left




							def  A__      (				self):
												return self.right




							def  A__      (				self):
												return self.height




							def  A__      (				self   ,A__):
												lowercase							=						data




							def  A__      (				self   ,A__):
												lowercase							=						node




							def  A__      (				self   ,A__):
												lowercase							=						node





							def  A__      (				self   ,A__):
												lowercase							=						height



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					if node is None:
										return 0
					return node.get_height()



def        UpperCamelCase    (							lowerCAmelCase__ ,			lowerCAmelCase__		):
					'''simple docstring'''
					if a > b:
										return a
					return b



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					print('''left rotation node:''' ,			node.get_data()		)
					lowercase							=						node.get_left()
					assert ret is not None
					node.set_left(ret.get_right()		)
					ret.set_right(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(node.get_right()		) ,			get_height(node.get_left()		)		) + 1
					node.set_height(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(ret.get_right()		) ,			get_height(ret.get_left()		)		) + 1
					ret.set_height(lowerCAmelCase__		)
					return ret



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					print('''right rotation node:''' ,			node.get_data()		)
					lowercase							=						node.get_right()
					assert ret is not None
					node.set_right(ret.get_left()		)
					ret.set_left(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(node.get_right()		) ,			get_height(node.get_left()		)		) + 1
					node.set_height(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(ret.get_right()		) ,			get_height(ret.get_left()		)		) + 1
					ret.set_height(lowerCAmelCase__		)
					return ret



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					lowercase							=						node.get_left()
					assert left_child is not None
					node.set_left(left_rotation(lowerCAmelCase__		)		)
					return right_rotation(lowerCAmelCase__		)



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					lowercase							=						node.get_right()
					assert right_child is not None
					node.set_right(right_rotation(lowerCAmelCase__		)		)
					return left_rotation(lowerCAmelCase__		)



def        UpperCamelCase    (							lowerCAmelCase__ ,			lowerCAmelCase__		):
					'''simple docstring'''
					if node is None:
										return MyNode(lowerCAmelCase__		)
					if data < node.get_data():
										node.set_left(insert_node(node.get_left() ,			lowerCAmelCase__		)		)
										if (
										    get_height(node.get_left()		) - get_height(node.get_right()		) == 2
										):  # an unbalance detected
															lowercase							=						node.get_left()
															assert left_child is not None
															if (
															    data < left_child.get_data()
															):  # new node is the left child of the left child
																				lowercase							=						right_rotation(lowerCAmelCase__		)
															else:
																				lowercase							=						lr_rotation(lowerCAmelCase__		)
					else:
										node.set_right(insert_node(node.get_right() ,			lowerCAmelCase__		)		)
										if get_height(node.get_right()		) - get_height(node.get_left()		) == 2:
															lowercase							=						node.get_right()
															assert right_child is not None
															if data < right_child.get_data():
																				lowercase							=						rl_rotation(lowerCAmelCase__		)
															else:
																				lowercase							=						left_rotation(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(node.get_right()		) ,			get_height(node.get_left()		)		) + 1
					node.set_height(lowerCAmelCase__		)
					return node



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					while True:
										lowercase							=						root.get_right()
										if right_child is None:
															break
										lowercase							=						right_child
					return root.get_data()



def        UpperCamelCase    (							lowerCAmelCase__		):
					'''simple docstring'''
					while True:
										lowercase							=						root.get_left()
										if left_child is None:
															break
										lowercase							=						left_child
					return root.get_data()



def        UpperCamelCase    (							lowerCAmelCase__ ,			lowerCAmelCase__		):
					'''simple docstring'''
					lowercase							=						root.get_left()
					lowercase							=						root.get_right()
					if root.get_data() == data:
										if left_child is not None and right_child is not None:
															lowercase							=						get_left_most(lowerCAmelCase__		)
															root.set_data(lowerCAmelCase__		)
															root.set_right(del_node(lowerCAmelCase__ ,			lowerCAmelCase__		)		)
										elif left_child is not None:
															lowercase							=						left_child
										elif right_child is not None:
															lowercase							=						right_child
										else:
															return None
					elif root.get_data() > data:
										if left_child is None:
															print('''No such data'''		)
															return root
										else:
															root.set_left(del_node(lowerCAmelCase__ ,			lowerCAmelCase__		)		)
					else:  # root.get_data() < data
										if right_child is None:
															return root
										else:
															root.set_right(del_node(lowerCAmelCase__ ,			lowerCAmelCase__		)		)

					if get_height(lowerCAmelCase__		) - get_height(lowerCAmelCase__		) == 2:
										assert right_child is not None
										if get_height(right_child.get_right()		) > get_height(right_child.get_left()		):
															lowercase							=						left_rotation(lowerCAmelCase__		)
										else:
															lowercase							=						rl_rotation(lowerCAmelCase__		)
					elif get_height(lowerCAmelCase__		) - get_height(lowerCAmelCase__		) == -2:
										assert left_child is not None
										if get_height(left_child.get_left()		) > get_height(left_child.get_right()		):
															lowercase							=						right_rotation(lowerCAmelCase__		)
										else:
															lowercase							=						lr_rotation(lowerCAmelCase__		)
					lowercase							=						my_max(get_height(root.get_right()		) ,			get_height(root.get_left()		)		) + 1
					root.set_height(lowerCAmelCase__		)
					return root







class 				lowercase		:




							def __init__(				self):
												lowercase							=						None




							def  A__      (				self):
												return get_height(self.root)




							def  A__      (				self   ,A__):
												print('''insert:''' + str(A__))
												lowercase							=						insert_node(self.root   ,A__)




							def  A__      (				self   ,A__):
												print('''delete:''' + str(A__))
												if self.root is None:
																	print('''Tree is empty!''')
																	return
												lowercase							=						del_node(self.root   ,A__)





							def __str__(				self   ,):  # a level traversale, gives a more intuitive look on the tree
												lowercase							=						''''''
												lowercase							=						MyQueue()
												q.push(self.root)
												lowercase							=						self.get_height()
												if layer == 0:
																	return output
												lowercase							=						0
												while not q.is_empty():
																	lowercase							=						q.pop()
																	lowercase							=						''' ''' * int(math.pow(2   ,layer - 1))
																	output += space
																	if node is None:
																						output += "*"
																						q.push(A__)
																						q.push(A__)
																	else:
																						output += str(node.get_data())
																						q.push(node.get_left())
																						q.push(node.get_right())
																	output += space
																	lowercase							=						cnt + 1
																	for i in range(1_0_0):
																						if cnt == math.pow(2   ,A__) - 1:
																											lowercase							=						layer - 1
																											if layer == 0:
																																output += "\n*************************************"
																																return output
																											output += "\n"
																											break
												output += "\n*************************************"
												return output



def        UpperCamelCase    (							):
					'''simple docstring'''
					import doctest

					doctest.testmod()


if __name__ == "__main__":
							_test()
							lowercase__		:Union[str, Any]   =    AVLtree()
							lowercase__		:List[str]   =    list(range(10))
							random.shuffle(lst)
							for i in lst:
														t.insert(i)
														print(str(t))
							random.shuffle(lst)
							for i in lst:
														t.del_node(i)
														print(str(t))









'''simple docstring'''






from manim import *

class 				SCREAMING_SNAKE_CASE(							A__			):







	"""simple docstring"""






	def      A	(						self			:     Union[str, Any]		)			->		List[str]:
								UpperCAmelCase :       Optional[Any] 							=		Rectangle(height=0.5		,			width=0.5		)
								UpperCAmelCase :       str 							=		Rectangle(height=0.46		,			width=0.46		).set_stroke(width=0		)

								UpperCAmelCase :       Tuple 							=		[mem.copy() for i in range(6		)]
								UpperCAmelCase :       Optional[int] 							=		[mem.copy() for i in range(6		)]
								UpperCAmelCase :       Dict 							=		VGroup(*__snake_case		).arrange(__snake_case		,			buff=0		)
								UpperCAmelCase :       Any 							=		VGroup(*__snake_case		).arrange(__snake_case		,			buff=0		)
								UpperCAmelCase :       Union[str, Any] 							=		VGroup(__snake_case		,			__snake_case		).arrange(__snake_case		,			buff=0		)
								UpperCAmelCase :       Optional[Any] 							=		Text('''CPU'''		,			font_size=24		)
								UpperCAmelCase :       Union[str, Any] 							=		Group(__snake_case		,			__snake_case		).arrange(__snake_case		,			buff=0.5		,			aligned_edge=__snake_case		)
								cpu.move_to([-2.5, -0.5, 0]		)
								self.add(__snake_case		)

								UpperCAmelCase :       Optional[Any] 							=		[mem.copy() for i in range(4		)]
								UpperCAmelCase :       Union[str, Any] 							=		VGroup(*__snake_case		).arrange(__snake_case		,			buff=0		)
								UpperCAmelCase :       List[str] 							=		Text('''GPU'''		,			font_size=24		)
								UpperCAmelCase :       Dict 							=		Group(__snake_case		,			__snake_case		).arrange(__snake_case		,			buff=0.5		,			aligned_edge=__snake_case		)
								gpu.move_to([-1, -1, 0]		)
								self.add(__snake_case		)

								UpperCAmelCase :       int 							=		[mem.copy() for i in range(6		)]
								UpperCAmelCase :       Union[str, Any] 							=		VGroup(*__snake_case		).arrange(__snake_case		,			buff=0		)

								UpperCAmelCase :       List[str] 							=		Text('''Model'''		,			font_size=24		)
								UpperCAmelCase :       Tuple 							=		Group(__snake_case		,			__snake_case		).arrange(__snake_case		,			buff=0.5		,			aligned_edge=__snake_case		)
								model.move_to([3, -1.0, 0]		)
								self.add(__snake_case		)

								UpperCAmelCase :       Any 							=		[]
								for i, rect in enumerate(__snake_case		):
															rect.set_stroke(__snake_case		)
															# target = fill.copy().set_fill(YELLOW, opacity=0.7)
															# target.move_to(rect)
															# self.add(target)

															UpperCAmelCase :       Dict 							=		Rectangle(height=0.46 / 4		,			width=0.46 / 3		).set_stroke(width=0.0		).set_fill(__snake_case		,			opacity=0.7		)

															if i == 0:
																						cpu_target.next_to(cpu_left_col_base[0].get_corner(DOWN + LEFT		)		,			buff=0.02		,			direction=__snake_case		)
																						cpu_target.set_x(cpu_target.get_x() + 0.1		)
															elif i == 3:
																						cpu_target.next_to(cpu_targs[0]		,			direction=__snake_case		,			buff=0.0		)
															else:
																						cpu_target.next_to(cpu_targs[i - 1]		,			direction=__snake_case		,			buff=0.0		)
															self.add(__snake_case		)
															cpu_targs.append(__snake_case		)

								UpperCAmelCase :       int 							=		[mem.copy() for i in range(6		)]
								UpperCAmelCase :       int 							=		VGroup(*__snake_case		).arrange(__snake_case		,			buff=0		)

								UpperCAmelCase :       Any 							=		Text('''Loaded Checkpoint'''		,			font_size=24		)
								UpperCAmelCase :       Union[str, Any] 							=		Group(__snake_case		,			__snake_case		).arrange(__snake_case		,			aligned_edge=__snake_case		,			buff=0.4		)
								checkpoint.move_to([3, 0.5, 0]		)

								UpperCAmelCase :       Optional[int] 							=		Square(side_length=2.2		)
								key.move_to([-5, 2, 0]		)

								UpperCAmelCase :       str 							=		MarkupText(
								    F"""<b>Key:</b>\n\n<span fgcolor='{YELLOW}'>●</span> Empty Model"""		,			font_size=18		,			)

								key_text.move_to([-5, 2.4, 0]		)

								self.add(__snake_case		,			__snake_case		)

								UpperCAmelCase :       Tuple 							=		MarkupText(
								    F"""<span fgcolor='{BLUE}'>●</span> Checkpoint"""		,			font_size=18		,			)

								blue_text.next_to(__snake_case		,			DOWN * 2.4		,			aligned_edge=key_text.get_left()		)

								UpperCAmelCase :       List[Any] 							=		MarkupText(
								    F"""Next, a <i><span fgcolor=\"{BLUE}\">second</span></i> model is loaded into memory,\nwith the weights of a <span fgcolor=\"{BLUE}\">single shard</span>."""		,			font_size=24		,			)
								step_a.move_to([2, 2, 0]		)
								self.play(Write(__snake_case		)		,			Write(__snake_case		)		)

								self.play(Write(__snake_case		,			run_time=1		)		,			Create(__snake_case		,			run_time=1		)		)

								UpperCAmelCase :       Tuple 							=		[]
								UpperCAmelCase :       int 							=		[]
								for i, rect in enumerate(__snake_case		):
															UpperCAmelCase :       Any 							=		fill.copy().set_fill(__snake_case		,			opacity=0.7		)
															target.move_to(__snake_case		)
															first_animations.append(GrowFromCenter(__snake_case		,			run_time=1		)		)

															UpperCAmelCase :       List[str] 							=		target.copy()
															cpu_target.generate_target()
															if i < 5:
																						cpu_target.target.move_to(cpu_left_col_base[i + 1]		)
															else:
																						cpu_target.target.move_to(cpu_right_col_base[i - 5]		)
															second_animations.append(MoveToTarget(__snake_case		,			run_time=1.5		)		)

								self.play(*__snake_case		)
								self.play(*__snake_case		)
								self.wait()





