Problem:
Binary Search Tree III

Write a program which performs the following operations to a binary search tree $T$ by adding delete operation to B: Binary Search Tree II.

insert $k$: Insert a node containing $k$ as key into $T$.

find $k$: Report whether $T$ has a node containing $k$.

delete $k$: Delete a node containing $k$.

print: Print the keys of the binary search tree by inorder tree walk and preorder tree walk respectively.

The operation delete $k$ for deleting a given node $z$ containing key $k$ from $T$ can be implemented by an algorithm which considers the following cases:

If $z$ has no children, we modify its parent $z.p$ to replace $z$ with NIL as its child (delete $z$).

If $z$ has only a single child, we "splice out" $z$ by making a new link between its child and its parent.

If $z$ has two children, we splice out $z$'s successor $y$ and replace $z$'s key with $y$'s key.

Input

In the first line, the number of operations $m$ is given. In the following $m$ lines, operations represented by insert $k$, find $k$, delete $k$ or print are given.

Output

For each find $k$ operation, print "yes" if $T$ has a node containing $k$, "no" if not.

In addition, for each print operation, print a list of keys obtained by inorder tree walk and preorder tree walk in a line respectively. Put a space character before each key

Constraints

The number of operations $\leq 500,000$

The number of print operations $\leq 10$.

$-2,000,000,000 \leq key \leq 2,000,000,000$

The height of the binary tree does not exceed 100 if you employ the above pseudo code.

The keys in the binary search tree are all different.

Sample Input 1

18
insert 8
insert 2
insert 3
insert 7
insert 22
insert 1
find 1
find 2
find 3
find 4
find 5
find 6
find 7
find 8
print
delete 3
delete 7
print

Sample Output 1

yes
yes
yes
no
no
no
yes
yes
1 2 3 7 8 22
8 2 1 3 7 22
1 2 8 22
8 2 1 22

Reference

Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. The MIT Press.

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static System.Math;
using Forest;

namespace CSharpSpiral {
	class Program {
		static void Main(string[] args) {
			var sw = new StreamWriter(Console.OpenStandardOutput()) {
				AutoFlush=
#if DEBUG
			true
#else
			false
#endif
			};
			Console.SetOut(sw);
			new Program().Solve(new ConsoleInput(
#if DEBUG
			new StreamReader("../../../inputData.txt")
#else
			Console.In
#endif
			, ' '));
			Console.Out.Flush();
		}
		public void Solve(ConsoleInput cin) {
			var N = cin.ReadInt;
			var Tree = new BinarySearchTree<int>();
			for(int i = 0; i<N; i++) {
				var query = cin.ReadLine.Split(' ');
				var number = query.Length>1 ? int.Parse(query[1]) : -1;
				switch(query[0][0]) {
					case 'i':
						Tree.Insert(number);
						break;
					case 'p':
						var sb = new StringBuilder();
						Tree.DFS(null, s => { sb.Append(" "+s.Value); }, null);
						Console.WriteLine(sb.ToString());
						sb.Clear();
						Tree.DFS(s => { sb.Append(" "+s.Value); }, null, null);
						Console.WriteLine(sb.ToString());
						sb.Clear();
						break;
					case 'f':
						Console.WriteLine(Tree.Contains(number) ? "yes" : "no");
						break;
					case 'd':
						Tree.Delete(number);
						break;
				}
			}
		}

	}
	static class ExtendClass {
		public static void Swap<T>(this T[] A, int x, int y) {
			var tmp = A[x];
			A[x]=A[y];
			A[y]=tmp;
		}
		public static string Join<T>(this IEnumerable<T> X, string separator = " ") => string.Join(separator, X);
		public static IEnumerable<int> Indices<T>(this T[] X) => Enumerable.Range(0, X.Length);
		public static IEnumerable<int> Indices<T>(this T[,] X, int dim)
			=> Enumerable.Range(0, X.GetLength(dim));
		//public static IEnumerable<(int i1, int i2)> Indices<T>(this T[,] X)
		//	=> X.Indices(0).SelectMany(i => X.Indices(1).Select((i, j) => (i, j)));
		public static string Join<T>(this T[,] X, string separatorD2 = ",", string separatorD1 = "\n")
			=> X.Indices(0).Select(
				i => X.Indices(1).Select(j => X[i, j]).Join(separatorD2)
			).Join(separatorD1);
	}
	class ConsoleInput {
		private readonly TextReader _stream;
		private readonly char _separator = ' ';
		private readonly Queue<string> inputStream;
		public ConsoleInput(TextReader stream, char separator = ' ') {
			this._separator=separator;
			this._stream=stream;
			inputStream=new Queue<string>();
		}
		public string Read {
			get {
				if(inputStream.Count!=0) return inputStream.Dequeue();
				string[] tmp = _stream.ReadLine().Split(_separator);
				for(int i = 0; i<tmp.Length; ++i)
					inputStream.Enqueue(tmp[i]);
				return inputStream.Dequeue();
			}
		}
		public string ReadLine { get { return _stream.ReadLine(); } }
		public int ReadInt { get { return int.Parse(Read); } }
		public long ReadLong { get { return long.Parse(Read); } }
		public double ReadDouble { get { return double.Parse(Read); } }
		public string[] ReadStrArray(long N) {
			var ret = new string[N];
			for(long i = 0; i<N; ++i)
				ret[i]=Read;
			return ret;
		}
		public int[] ReadIntArray(long N) { var ret = new int[N]; for(long i = 0; i<N; ++i) ret[i]=ReadInt; return ret; }
		public long[] ReadLongArray(long N) { var ret = new long[N]; for(long i = 0; i<N; ++i) ret[i]=ReadLong; return ret; }
		public double[] ReadDoubleArray(long N) { var ret = new double[N]; for(long i = 0; i<N; ++i) ret[i]=ReadDouble; return ret; }
		public bool isEOF {
			get { return _stream.Peek()==-1; }
		}
	}

}
namespace Forest {
	class TreeNode<T> {
		public virtual TreeNode<T> Parent { get; set; }
		public T Value { get; set; }
		public int Id { get; set; }
		public int Order { get; set; }
		public virtual List<TreeNode<T>> Children { get; set; } = new List<TreeNode<T>>();
		public virtual bool isRoot { get { return Parent==null; } }
		public virtual bool isLeaf { get { return !Children.Any(); } }
		public bool isInternal { get { return !isRoot&&!isLeaf; } }
		public virtual int Depth {
			get {
				var count = 0;
				var P = this;
				while(!P.isRoot) {
					P=P.Parent;
					count++;
				}
				return count;
			}
		}
		public int Height {
			get {
				if(isLeaf) return 0;
				return Children.Select(X => X.Height).Max()+1;
			}
		}
		public virtual int Degree { get { return Children.Count(); } }

		public void AdoptMany(List<TreeNode<T>> children) {
			Children=children;
			foreach(var node in children)
				node.Parent=this;
		}
		public void AdoptMany(TreeNode<T>[] Base, IEnumerable<int> call) {
			var children = call.Select(k => Base[k]).ToList();
			AdoptMany(children);
		}
		public void Adopt(TreeNode<T> child) {
			Children.Add(child);
			child.Parent=this;
		}
	}
	class BinNode<T>: TreeNode<T> {
		public new BinNode<T> Parent { get; set; }
		public BinNode<T> Left { get; set; }
		public BinNode<T> Right { get; set; }
		public new List<BinNode<T>> Children {
			get { return new BinNode<T>[] { Left, Right }.Where(x => x!=null).ToList(); }
		}
		public override int Depth {
			get {
				var count = 0;
				var P = this;
				while(!P.isRoot) {
					P=P.Parent;
					count++;
				}
				return count;
			}
		}
		public new bool isRoot { get { return Parent==null; } }
		public override bool isLeaf { get { return Left==null&&Right==null; } }
		public override int Degree {
			get { return (Left!=null ? 1 : 0)+(Right!=null ? 1 : 0); }
		}
		public void Adopt(BinNode<T> left, BinNode<T> right) {
			Left=left; Right=right;
			if(left!=null) left.Parent=this; if(right!=null) right.Parent=this;
		}
		public BinNode<T> Sibling {
			get { return isRoot ? null : Equals(Parent.Left) ? Parent.Right : Parent.Left; }
		}
		public static void GetHeight(BinNode<T>[] Nodes, out int[] Res) {
			Res=new int[Nodes.Length];
			foreach(var root in Nodes.Where(n => n.isRoot)) {
				GetHeight(root, Res);
			}
		}
		private static void GetHeight(BinNode<T> now, int[] Res) {
			if(now.isLeaf||!now.Children.Any()) { Res[now.Id]=0; return; }
			foreach(var child in now.Children) {
				GetHeight(child, Res);
			}
			Res[now.Id]=now.Children.Max(c => Res[c.Id])+1;
		}
		internal static void DFS(BinNode<T> now,
			Func<BinNode<T>, bool> OnEnter, Func<BinNode<T>, bool> OnMiddle, Func<BinNode<T>, bool> OnLeave
		) {
			if(now==null) return;
			if(OnEnter?.Invoke(now)==true) return;
			DFS(now.Left, OnEnter, OnMiddle, OnLeave);
			if(OnMiddle?.Invoke(now)==true) return;
			DFS(now.Right, OnEnter, OnMiddle, OnLeave);
			if(OnLeave?.Invoke(now)==true) return;
		}
		internal static void DFS(BinNode<T> now,
			Action<BinNode<T>> OnEnter, Action<BinNode<T>> OnMiddle, Action<BinNode<T>> OnLeave
		) {
			if(now==null) return;
			OnEnter?.Invoke(now);
			DFS(now.Left, OnEnter, OnMiddle, OnLeave);
			OnMiddle?.Invoke(now);
			DFS(now.Right, OnEnter, OnMiddle, OnLeave);
			OnLeave?.Invoke(now);
		}
		public void PreLabel() {
			var count = 0;
			DFS(this, b => b.Order=count++, null, null);
		}
		public void InLabel() {
			var count = 0;
			DFS(this, null, b => b.Order=count++, null);
		}
		public void PostLabel() {
			var count = 0;
			DFS(this, null, null, b => b.Order=count++);
		}
		public List<BinNode<T>> PreOrder() {
			var order = new List<BinNode<T>>();
			DFS(this, b => order.Add(b), null, null);
			return order;
		}
		public List<BinNode<T>> InOrder() {
			var order = new List<BinNode<T>>();
			DFS(this, null, b => order.Add(b), null);
			return order;
		}
		public List<BinNode<T>> PostOrder() {
			var order = new List<BinNode<T>>();
			DFS(this, null, null, b => order.Add(b));
			return order;
		}
		internal BinNode<T> Leftest() {
			if(this==null) return null;
			var tmp = this;
			while(tmp.Left!=null)
				tmp=tmp.Left;
			return tmp;
		}
		internal bool isLeftSide() => this==Parent?.Left;
		internal bool isRightSide() => this==Parent?.Right;
		internal void ReAdopt(BinNode<T> neo) {
			if(isLeftSide()) Parent.Left=neo;
			else if(isRightSide()) Parent.Right=neo;
		}
		internal void ClearRelation() {
			Parent=null; Left=null; Right=null;
		}
		public override string ToString() {
			return $"{(Parent!=null?Parent.Value.ToString():"")} -> {(this!=null ? Value.ToString() : "")} "+
			$" -> {(Left!=null?Left.Value.ToString():"")}, {(Right!=null ? Right.Value.ToString() : "")}";
		}
	}
	class BinarySearchTree<T> where T : IComparable<T> {
		public BinNode<T> Root { get; private set; }
		public int count { get; set; } = 0;
		public Comparer<T> comparer { get; } = Comparer<T>.Create((i, j) => i.CompareTo(j));
		private int Collate(T a, T b) => comparer.Compare(a, b);
		private int Collate(BinNode<T> A, BinNode<T> B)
			=> Collate(A.Value, B.Value);
		public void Insert(T value)
			=> Insert(new BinNode<T> { Value=value, Id=count++ });
		public void Insert(BinNode<T> newComer) {
			var newParent = default(BinNode<T>);
			var parentDetector = Root;
			while(parentDetector!=null) {
				newParent=parentDetector;
				parentDetector=
					Collate(newComer, parentDetector)<0 ? parentDetector.Left : parentDetector.Right;
			}
			newComer.Parent=newParent;

			if(newParent==null) {
				Root=newComer;
			} else if(Collate(newComer, newParent)<0) {
				newParent.Left=newComer;
			} else {
				newParent.Right=newComer;
			}
		}
		public bool Contains(T value) => Find(value)!=null;
		public BinNode<T> Find(T value) {
			var tmp = Root;
			while(tmp!=null) {
				var collation = Collate(value, tmp.Value);
				if(collation==0) return tmp;
				else tmp=collation<0 ? tmp.Left : tmp.Right;
			}
			return null;
		}
		public void Delete(T value) {
			var Z = Find(value);
			if(Z==null) return;
			Delete(Z);
		}
		public void Delete(BinNode<T> t) {
			var p = t.Parent;
			switch(t.Children.Count()) {
				case 0:
					if(t.isLeftSide())
						p.Left=null;
					else if(t.isRightSide())
						p.Right=null;
					else
						Root=t;
					t.ClearRelation();
					break;
				case 1:
					var Child = t.Children.First();
					Child.Parent=p;
					t.ReAdopt(Child);
					if(Root==t) Root=Child;
					t.ClearRelation();
					break;
				default:
					var Next = t.Right.Leftest();
					t.Value=Next.Value;
					if(Next.isLeftSide()) Next.Parent.Left=null;
					else if(Next.isRightSide()) Next.Parent.Right=null;
					Next.ClearRelation();
					break;
			}
		}
		public void DFS(
			Func<BinNode<T>, bool> OnEnter, Func<BinNode<T>, bool> OnMiddle, Func<BinNode<T>, bool> OnLeave
		) {
			BinNode<T>.DFS(Root, OnEnter, OnMiddle, OnLeave);
		}
		public void DFS(
			Action<BinNode<T>> OnEnter, Action<BinNode<T>> OnMiddle, Action<BinNode<T>> OnLeave
		) {
			BinNode<T>.DFS(Root, OnEnter, OnMiddle, OnLeave);
		}
	}
}