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 _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()