def _put(self, node: BinaryTreeNode, key, value):
        if key == node.key:
            node.value = value
        elif key < node.key:
            if node.has_left_child():
                self._put(node.left, key, value)
            else:
                node.left = BinaryTreeNode(key, value, parent=node)
        else:
            if node.has_right_child():
                self._put(node.right, key, value)
            else:
                node.right = BinaryTreeNode(key, value, parent=node)

        node.update_size()
    def _delete(self, node: BinaryTreeNode, key):
        if not node:
            return None
        if key < node.key:
            node.left = self._delete(node.left, key)
        elif key > node.key:
            node.right = self._delete(node.right, key)
        else:
            if not node.right:
                return node.left
            if not node.left:
                return node.right
            successor = self._delete_min(node.right)
            node.parent.set_child(successor)
            successor.set_left(node.left)
            successor.set_right(node.right)
            node = successor

        node.update_size()
        return node
    def _put(self, node: BinaryTreeNode, key, value):
        # same as bst.
        if key == node.key:
            node.value = value
            return
        elif key < node.key:
            if node.has_left_child():
                self._put(node.left, key, value)
            else:
                node.left = BinaryTreeNode(key, value, parent=node)
        else:
            if node.has_right_child():
                self._put(node.right, key, value)
            else:
                node.right = BinaryTreeNode(key, value, parent=node)

        # rotate and colors change
        if self.is_red(node.right) and not self.is_red(node.left):
            node = self.rotate_left(node)
        if self.is_red(node.left) and node.left and self.is_red(node.left.left):
            node = self.rotate_right(node)
        self.flip_colors(node)

        node.update_size()