//create a new interval tree node
		private static ITNode newNode(Interval i){

			ITNode temp = new ITNode (i, i.high, null, null);
			return temp;
		}
		public int max { get; set;} //maximum high value in subtree rooted with this node
		public ITNode(Interval i, int m, ITNode l, ITNode r){
			this.i = i;
			this.max = m;
			this.left = l;
			this.right = r;
		}
		public ITNode(Interval i){
			this.i = i;
			this.left = null;
			this.right = null;
		}
		//use interval BST to store previous k intervals
		public static bool containsNearbyAlmostDuplicate(int[] arr, int k, int l){
			if (arr.Length == 0)
				return false;
			Interval interval = new Interval (arr [0] - l / 2, arr [0] + l / 2); //put first element into tree
			ITNode root = new ITNode (interval, interval.high, null, null);
			for(int i=1;i<arr.Length;i++){
				Interval curr = new Interval (arr [i] - l / 2, arr [i] + l / 2);
				if (IntervalTree.overlapSearch (root, curr)) //if overlap, return true
					return true;
				if (i >=k) {  //if tree size >= k, remove the earliest element from the tree
					Interval toDelete = new Interval (arr [i - k] - l / 2, arr [i - k] + l / 2);
					IntervalTree.delete (root, toDelete);
				}
				IntervalTree.insert (root, curr); //insert current interval to the tree
			}
			return false;
		}
		//Check if a given interval overlaps in the given interval tree
		public static bool overlapSearch(ITNode root, Interval i){

			//base case, tree is empty
			if(root == null) 
				return false;

			//if i overlaps with root
			if(doOverlap(root.i,i))
				return true;

			//if left child of root is present and max of left child is
			//greater than or equal to given interval, then i may overlap
			//with an interval in left subtree
			if (root.left != null && root.left.max >= i.low)
				return overlapSearch (root.left, i);

			//Else interval can only overlap with right subtree
			return overlapSearch (root.right, i);
		}
		//check if two given intervals overlap
		private static bool doOverlap(Interval i1, Interval i2){
			if (i1.low <= i2.high && i2.low <= i1.high)
				return true;
			else
				return false;
		}
		//delete the node containing the given interval from tree
		public static ITNode delete(ITNode root, Interval i){

			//base case
			if (root == null)
				return root;

			//get low value of root
			int l = root.i.low;

			//if i.low is smaller than root's low value,
			//then it lies in the left subtree
			if (i.low < l)
				root.left = delete (root.left, i);

			//if i.low is greater than root's low value,
			//then it lies in the right subtree
			else if (i.low > l)
				root.right = delete (root.right, i);

			//if i.low is equal to root's low value
			//then root is the node to be deleted
			else {

				//if root has only one child or no child
				if (root.left == null) {
					ITNode temp = root.right;
					return temp;
				} else if (root.right == null) {
					ITNode temp = root.left;
					return temp;
				} 
				//if root with two childre: get the inorder successor
				//which is the smallest in the right subtree
				else {

					//Node with two children: get the inorder successor
					ITNode temp = minValueNode (root.right);

					//copy inorder successor's content to this node
					root.i = temp.i;
					root.max = temp.max;

					//delete the inorder successor
					root.right = delete (root.right, temp.i);
				}
			}
			return root;
		}
		//Insert a new Interval Search Tree node
		//this is very similar to BST Insert. The low value of interval
		//is used to maintain BST property
		public static ITNode insert(ITNode root, Interval i){

			//base case: tree is empty, new node become root
			if (root == null)
				return newNode (i);

			//get low value of interval of root
			int l = root.i.low;

			//if i.low is smaller than root's low value,
			//then i goes to the left subtree
			if (i.low < l)
				root.left = insert (root.left, i);

			//else, i goes to the right subtree
			else
				root.right = insert (root.right, i);

			//update the max value of this ancestor if needed
			if (root.max < i.high)
				root.max = i.high;
			return root;
		}