





'''simple docstring'''


class 				lowerCAmelCase_						:




 def __init__(		self     ,       _lowerCAmelCase						)      ->							str:
     _lowerCAmelCase		     = val
     # Number of nodes in left subtree
     _lowerCAmelCase		     = 0
     _lowerCAmelCase		     = None
     _lowerCAmelCase		     = None
     _lowerCAmelCase		     = None





 def 							_snake_case				(		self     ,       _lowerCAmelCase						)      ->							Optional[Any]:
     assert self.left_tree_size == other.left_tree_size, "Unequal Sizes of Blocks"

     if self.val < other.val:
         _lowerCAmelCase		     = self.right
         _lowerCAmelCase		     = None
         if self.right:
             _lowerCAmelCase		     = other
         _lowerCAmelCase		     = other
         _lowerCAmelCase		     = self.left_tree_size * 2 + 1
         return self
     else:
         _lowerCAmelCase		     = other.right
         _lowerCAmelCase		     = None
         if other.right:
             _lowerCAmelCase		     = self
         _lowerCAmelCase		     = self
         _lowerCAmelCase		     = other.left_tree_size * 2 + 1
         return other







class 				lowerCAmelCase_						:




 def __init__(		self     ,       _lowerCAmelCase=None     ,       _lowerCAmelCase=None     ,       _lowerCAmelCase=0						)      ->							List[Any]:
     _lowerCAmelCase		     = heap_size
     _lowerCAmelCase		     = bottom_root
     _lowerCAmelCase		     = min_node




 def 							_snake_case				(		self     ,       _lowerCAmelCase						)      ->							Dict:

     # Empty heaps corner cases
     if other.size == 0:
         return None
     if self.size == 0:
         _lowerCAmelCase		     = other.size
         _lowerCAmelCase		     = other.bottom_root
         _lowerCAmelCase		     = other.min_node
         return None
     # Update size
     _lowerCAmelCase		     = self.size + other.size

     # Update min.node
     if self.min_node.val > other.min_node.val:
         _lowerCAmelCase		     = other.min_node
     # Merge

     # Order roots by left_subtree_size
     _lowerCAmelCase		     = []
     _lowerCAmelCase     ,     _lowerCAmelCase		     = self.bottom_root, other.bottom_root
     while i or j:
         if i and ((not j) or i.left_tree_size < j.left_tree_size):
             combined_roots_list.append((i, True)						)
             _lowerCAmelCase		     = i.parent
         else:
             combined_roots_list.append((j, False)						)
             _lowerCAmelCase		     = j.parent
        # Insert links between them
     for i in range(len(_lowerCAmelCase						) - 1						):
         if combined_roots_list[i][1] != combined_roots_list[i + 1][1]:
             _lowerCAmelCase		     = combined_roots_list[i + 1][0]
             _lowerCAmelCase		     = combined_roots_list[i][0]
        # Consecutively merge roots with same left_tree_size
     _lowerCAmelCase		     = combined_roots_list[0][0]
     while i.parent:
         if (
             (i.left_tree_size == i.parent.left_tree_size) and (not i.parent.parent)
         ) or (
             i.left_tree_size == i.parent.left_tree_size
             and i.left_tree_size != i.parent.parent.left_tree_size
         ):
             # Neighbouring Nodes
             _lowerCAmelCase		     = i.left
             _lowerCAmelCase		     = i.parent.parent

             # Merging trees
             _lowerCAmelCase		     = i.merge_trees(i.parent						)

             # Updating links
             _lowerCAmelCase		     = previous_node
             _lowerCAmelCase		     = next_node
             if previous_node:
                 _lowerCAmelCase		     = i
             if next_node:
                 _lowerCAmelCase		     = i
         else:
             _lowerCAmelCase		     = i.parent
        # Updating self.bottom_root
     while i.left:
         _lowerCAmelCase		     = i.left
     _lowerCAmelCase		     = i

     # Update other
     _lowerCAmelCase		     = self.size
     _lowerCAmelCase		     = self.bottom_root
     _lowerCAmelCase		     = self.min_node

     # Return the merged heap
     return self




 def 							_snake_case				(		self     ,       _lowerCAmelCase						)      ->							Optional[int]:
     if self.size == 0:
         _lowerCAmelCase		     = Node(_lowerCAmelCase						)
         _lowerCAmelCase		     = 1
         _lowerCAmelCase		     = self.bottom_root
     else:
         # Create new node
         _lowerCAmelCase		     = Node(_lowerCAmelCase						)

         # Update size
         self.size += 1

         # update min_node
         if val < self.min_node.val:
             _lowerCAmelCase		     = new_node
         # Put new_node as a bottom_root in heap
         _lowerCAmelCase		     = new_node
         _lowerCAmelCase		     = self.bottom_root
         _lowerCAmelCase		     = new_node

         # Consecutively merge roots with same left_tree_size
         while (
             self.bottom_root.parent
             and self.bottom_root.left_tree_size
             == self.bottom_root.parent.left_tree_size
         ):
             # Next node
             _lowerCAmelCase		     = self.bottom_root.parent.parent

             # Merge
             _lowerCAmelCase		     = self.bottom_root.merge_trees(self.bottom_root.parent						)

             # Update Links
             _lowerCAmelCase		     = next_node
             _lowerCAmelCase		     = None
             if next_node:
                 _lowerCAmelCase		     = self.bottom_root




 def 							_snake_case				(		self						)      ->							Any:
     return self.min_node.val




 def 							_snake_case				(		self						)      ->							Union[str, Any]:
     return self.size == 0




 def 							_snake_case				(		self						)      ->							int:
     _lowerCAmelCase		     = self.min_node.val

     # Last element in heap corner case
     if self.size == 1:
         # Update size
         _lowerCAmelCase		     = 0

         # Update bottom root
         _lowerCAmelCase		     = None

         # Update min_node
         _lowerCAmelCase		     = None

         return min_value
     # No right subtree corner case
     # The structure of the tree implies that this should be the bottom root
     # and there is at least one other root
     if self.min_node.right is None:
         # Update size
         self.size -= 1

         # Update bottom root
         _lowerCAmelCase		     = self.bottom_root.parent
         _lowerCAmelCase		     = None

         # Update min_node
         _lowerCAmelCase		     = self.bottom_root
         _lowerCAmelCase		     = self.bottom_root.parent
         while i:
             if i.val < self.min_node.val:
                 _lowerCAmelCase		     = i
             _lowerCAmelCase		     = i.parent
         return min_value
     # General case
     # Find the BinomialHeap of the right subtree of min_node
     _lowerCAmelCase		     = self.min_node.right
     _lowerCAmelCase		     = None
     _lowerCAmelCase		     = bottom_of_new
     _lowerCAmelCase		     = 1

     # Size, min_node and bottom_root
     while bottom_of_new.left:
         _lowerCAmelCase		     = size_of_new * 2 + 1
         _lowerCAmelCase		     = bottom_of_new.left
         if bottom_of_new.val < min_of_new.val:
             _lowerCAmelCase		     = bottom_of_new
        # Corner case of single root on top left path
     if (not self.min_node.left) and (not self.min_node.parent):
         _lowerCAmelCase		     = size_of_new
         _lowerCAmelCase		     = bottom_of_new
         _lowerCAmelCase		     = min_of_new
         # print("Single root, multiple nodes case")
         return min_value
     # Remaining cases
     # Construct heap of right subtree
     _lowerCAmelCase		     = BinomialHeap(
         bottom_root=_lowerCAmelCase     ,       min_node=_lowerCAmelCase     ,       heap_size=_lowerCAmelCase						)

     # Update size
     _lowerCAmelCase		     = self.size - 1 - size_of_new

     # Neighbour nodes
     _lowerCAmelCase		     = self.min_node.left
     _lowerCAmelCase		     = self.min_node.parent

     # Initialize new bottom_root and min_node
     _lowerCAmelCase		     = previous_node or next_node
     _lowerCAmelCase		     = next_node

     # Update links of previous_node and search below for new min_node and
     # bottom_root
     if previous_node:
         _lowerCAmelCase		     = next_node

         # Update bottom_root and search for min_node below
         _lowerCAmelCase		     = previous_node
         _lowerCAmelCase		     = previous_node
         while self.bottom_root.left:
             _lowerCAmelCase		     = self.bottom_root.left
             if self.bottom_root.val < self.min_node.val:
                 _lowerCAmelCase		     = self.bottom_root
     if next_node:
         _lowerCAmelCase		     = previous_node

         # Search for new min_node above min_node
         _lowerCAmelCase		     = next_node
         while i:
             if i.val < self.min_node.val:
                 _lowerCAmelCase		     = i
             _lowerCAmelCase		     = i.parent
        # Merge heaps
     self.merge_heaps(_lowerCAmelCase						)

     return min_value




 def 							_snake_case				(		self						)      ->							Tuple:
     _lowerCAmelCase		     = self.bottom_root
     while top_root.parent:
         _lowerCAmelCase		     = top_root.parent
     # preorder
     _lowerCAmelCase		     = []
     self.__traversal(_lowerCAmelCase     ,       _lowerCAmelCase						)
     return heap_pre_order




 def 							_snake_case				(		self     ,       _lowerCAmelCase     ,       _lowerCAmelCase     ,       _lowerCAmelCase=0						)      ->							Any:
     if curr_node:
         preorder.append((curr_node.val, level)						)
         self.__traversal(curr_node.left     ,       _lowerCAmelCase     ,       level + 1						)
         self.__traversal(curr_node.right     ,       _lowerCAmelCase     ,       level + 1						)
     else:
         preorder.append(("#", level)						)





 def __str__(		self						)      ->							Any:
     if self.is_empty():
         return ""
     _lowerCAmelCase		     = self.pre_order()

     return "\n".join(("-" * level + str(_lowerCAmelCase						)) for value, level in preorder_heap						)


# Unit Tests
if __name__ == "__main__":
       import doctest

       doctest.testmod()









'''simple docstring'''


_SCREAMING_SNAKE_CASE			=							{
    "A": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"),
    "B": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"),
    "C": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"),
    "D": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"),
    "E": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"),
    "F": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"),
    "G": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"),
    "H": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"),
    "I": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"),
    "J": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"),
    "K": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"),
    "L": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"),
    "M": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"),
    "N": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"),
    "O": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"),
    "P": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"),
    "Q": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"),
    "R": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"),
    "S": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"),
    "T": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"),
    "U": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"),
    "V": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"),
    "W": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"),
    "X": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"),
    "Y": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"),
    "Z": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"),
}


def 		__a(SCREAMING_SNAKE_CASE_					:   str      ):



    '''simple docstring'''





    return [alphabet[char] for char in key.upper()]


def 		__a(SCREAMING_SNAKE_CASE_					:   str						,    SCREAMING_SNAKE_CASE_					:   str      ):



    '''simple docstring'''





    _lowerCAmelCase		     = ""
    _lowerCAmelCase		     = 0
    _lowerCAmelCase		     = generate_table(SCREAMING_SNAKE_CASE_      )
    for char in words.upper():
        cipher += get_opponent(table[count]						,    SCREAMING_SNAKE_CASE_      )
        _lowerCAmelCase		     = (count + 1) % len(SCREAMING_SNAKE_CASE_      )
    return cipher


def 		__a(SCREAMING_SNAKE_CASE_					:   str						,    SCREAMING_SNAKE_CASE_					:   str      ):



    '''simple docstring'''





    return encrypt(SCREAMING_SNAKE_CASE_						,    SCREAMING_SNAKE_CASE_      )


def 		__a(SCREAMING_SNAKE_CASE_					:   tuple[str, str]						,    SCREAMING_SNAKE_CASE_					:   str      ):



    '''simple docstring'''





    _lowerCAmelCase		     = 0 if char in table[0] else 1
    _lowerCAmelCase		     = table[row].index(SCREAMING_SNAKE_CASE_      )
    return row, col


def 		__a(SCREAMING_SNAKE_CASE_					:   tuple[str, str]						,    SCREAMING_SNAKE_CASE_					:   str      ):



    '''simple docstring'''





    _lowerCAmelCase     ,     _lowerCAmelCase		     = get_position(SCREAMING_SNAKE_CASE_						,    char.upper()      )
    if row == 1:
        return table[0][col]
    else:
        return table[1][col] if row == 0 else char


if __name__ == "__main__":
       import doctest

       doctest.testmod()  # Fist ensure that all our tests are passing...
       _SCREAMING_SNAKE_CASE			=							input("Enter key: ").strip()
       _SCREAMING_SNAKE_CASE			=							input("Enter text to encrypt: ").strip()
       _SCREAMING_SNAKE_CASE			=							encrypt(key, text)

       print(f'''Encrypted: {cipher_text}''')
       print(f'''Decrypted with key: {decrypt(key, cipher_text)}''')


