#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
#include <array>

using namespace std;

template<typename T>
struct Node {
	Node(const T& value) :value(value), parent(NULL), left(NULL), right(NULL) {}
	Node():Node(T()) {}
	T value;
	Node* parent;
	Node*left;
	Node*right;
};

template<typename T>
class BinarySearchTree
{
public:
	enum VisitOrder {
		ROOT = 0, LEFT = 1, RIGHT = 2
	};
	BinarySearchTree():root(NULL){}
	void insert(const T& value) {
		Node<T>* newNode(new Node<T>(value));
		Node<T>* parent = NULL;
		Node<T>* parentChild = NULL;
		{
			Node<T>* tempRootPtr = root;
			while (tempRootPtr != NULL) {
				parent = tempRootPtr;
				tempRootPtr = value < tempRootPtr->value ? tempRootPtr->left : tempRootPtr->right;
			}
		}
		newNode->parent = parent;
		if (parent == NULL) root = newNode;
		else (value < parent->value ? parent->left : parent->right) = newNode;
	}
	
	void printNodeKeys(const array<int, 3>& order) {//本当はこれを使ってオブジェクトの解放を自走すべきだが、未実装
		const array< function< Node<T>*(Node<T>*) >, 3> functionList = {
			  [&](Node<T>* node) {return node; }
			, [&](Node<T>* node) {return node->left; }
			, [&](Node<T>* node) {return node->right; }
		};

		function< void(Node<T>*) > printNodesImpl = [&](Node<T>* node){
			if (node == NULL)return;
			for (const auto& visitTargetIndex : order) {
				Node<T>* visitingNode = (functionList.at(visitTargetIndex))(node);
				if (visitingNode == node) cout << " " << visitingNode->value;
				else printNodesImpl(visitingNode);
			}
		};
		printNodesImpl(root);
	}


	Node<T>* find(const T& val) {
		Node<T>* currentNode = root;
		while (currentNode != NULL && currentNode->value != val) {
			currentNode = (val < currentNode->value ? currentNode->left : currentNode->right);
		}
		return currentNode;
	}

	bool deleteValue(const T& val) {//削除成功でtrueを返す
		Node<T>* targetNode = find(val);//削除する値を持つ節点を求める
		if (NULL == targetNode)return false;
		
		//削除する節点を決める
		//子が2つなら中間順巡回で次の一番最初の点を削除する（このときそのキーを自分にコピーしておく）
		//子が1or0なら、削除対象の節点を削除する
		Node<T>* deletedNode = targetNode;
		bool hasLeft = NULL != deletedNode->left;
		bool hasRight = NULL != deletedNode->right;
		if (hasLeft && hasRight) {

			deletedNode = targetNode->right;
			while (deletedNode->left != NULL) {
				deletedNode = deletedNode->left;
			}
			targetNode->value = deletedNode->value;
			hasLeft = NULL != deletedNode->left;
			hasRight = NULL != deletedNode->right;
		}

		//削除する前に、親子関係の帳尻合わせを行う
		Node<T>*& child = (hasLeft ? deletedNode->left : deletedNode->right);//子供がいない場合にはNULL
		if(child != NULL) child->parent = deletedNode->parent;//子の親を、自分の親に変更
		if (deletedNode->parent != NULL) {//親の子を、自分の子に変更（子がいない場合はNULLを入れて、自分がいたところの子がいないようにする）
			if (deletedNode == deletedNode->parent->left)  deletedNode->parent->left = child;
			else deletedNode->parent->right = child;
		}
		
		//削除対象を削除する
		delete deletedNode;
		
		return true;
	}

private:
	Node<T>* root;
};

template<typename T>
void execute(T& cin) {
	int n;
	cin >> n;
	string command;
	using Tree = BinarySearchTree<int>;
	Tree tree;
	command.reserve(6);//insertが最長で6
	for (int i = 0; i != n; ++i) {
		command.clear();
		cin >> command;
		if (command == "insert") {
			int key;
			cin >> key;
			tree.insert(key);
		}
		else if (command == "find") {
			int key;
			cin >> key;
			cout << (tree.find(key) != NULL ? "yes" : "no") << endl;
		}
		else if (command == "delete") {
			int key;
			cin >> key;
			tree.deleteValue(key);
		}
		else if(command =="print"){
			tree.printNodeKeys({ Tree::LEFT, Tree::ROOT, Tree::RIGHT });
			cout << endl;
			tree.printNodeKeys({ Tree::ROOT, Tree::LEFT, Tree::RIGHT });
			cout << endl;
		}
	}

}

int main()
{

	execute(cin);



	return 0;
}


Measured memory_bytes: 21916