}                                   //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;
 }
        //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));
        }
        //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);
        }
        //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);
        }
        //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);
        }
        //Given a non-empty BST, return the node with minimum key
        //value found in that tree. Note the entire tree does not
        //need to be searched
        private static ITNode minValueNode(ITNode node)
        {
            ITNode current = node;

            //loop down to find the leftmost child
            while (current.left != null)
            {
                current = current.left;
            }
            return(current);
        }
        //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;
		}
		//create a new interval tree node
		private static ITNode newNode(Interval i){

			ITNode temp = new ITNode (i, i.high, null, null);
			return temp;
		}
		//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);
		}
		//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;
		}
		//Given a non-empty BST, return the node with minimum key
		//value found in that tree. Note the entire tree does not
		//need to be searched
		private static ITNode minValueNode(ITNode node){
			ITNode current = node;

			//loop down to find the leftmost child
			while (current.left != null)
				current = current.left;
			return current;
		}
		//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;
		}