<p>You are given the <code>root</code> of a <strong>binary tree</strong> with <code>n</code> nodes. Each node is assigned a unique value from <code>1</code> to <code>n</code>. You are also given an array <code>queries</code> of size <code>m</code>.</p>

<p>You have to perform <code>m</code> <strong>independent</strong> queries on the tree where in the <code>i<sup>th</sup></code> query you do the following:</p>

<ul>
	<li><strong>Remove</strong> the subtree rooted at the node with the value <code>queries[i]</code> from the tree. It is <strong>guaranteed</strong> that <code>queries[i]</code> will <strong>not</strong> be equal to the value of the root.</li>
</ul>

<p>Return <em>an array </em><code>answer</code><em> of size </em><code>m</code><em> where </em><code>answer[i]</code><em> is the height of the tree after performing the </em><code>i<sup>th</sup></code><em> query</em>.</p>

<p><strong>Note</strong>:</p>

<ul>
	<li>The queries are independent, so the tree returns to its <strong>initial</strong> state after each query.</li>
	<li>The height of a tree is the <strong>number of edges in the longest simple path</strong> from the root to some node in the tree.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/09/07/binaryytreeedrawio-1.png" style="width: 495px; height: 281px;" />
<pre>
<strong>Input:</strong> root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4]
<strong>Output:</strong> [2]
<strong>Explanation:</strong> The diagram above shows the tree after removing the subtree rooted at node with value 4.
The height of the tree is 2 (The path 1 -&gt; 3 -&gt; 2).
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/09/07/binaryytreeedrawio-2.png" style="width: 301px; height: 284px;" />
<pre>
<strong>Input:</strong> root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]
<strong>Output:</strong> [3,2,3,2]
<strong>Explanation:</strong> We have the following queries:
- Removing the subtree rooted at node with value 3. The height of the tree becomes 3 (The path 5 -&gt; 8 -&gt; 2 -&gt; 4).
- Removing the subtree rooted at node with value 2. The height of the tree becomes 2 (The path 5 -&gt; 8 -&gt; 1).
- Removing the subtree rooted at node with value 4. The height of the tree becomes 3 (The path 5 -&gt; 8 -&gt; 2 -&gt; 6).
- Removing the subtree rooted at node with value 8. The height of the tree becomes 2 (The path 5 -&gt; 9 -&gt; 3).
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li>The number of nodes in the tree is <code>n</code>.</li>
	<li><code>2 &lt;= n &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= Node.val &lt;= n</code></li>
	<li>All the values in the tree are <strong>unique</strong>.</li>
	<li><code>m == queries.length</code></li>
	<li><code>1 &lt;= m &lt;= min(n, 10<sup>4</sup>)</code></li>
	<li><code>1 &lt;= queries[i] &lt;= n</code></li>
	<li><code>queries[i] != root.val</code></li>
</ul>

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

# Map (list) node reference, height, other_node_height (if enone, -1)

def tour(euler_tour, node, level):
    """
    This function performs an Euler tour (DFS) on the tree.
    :param euler_tour: list that stores the tour (node value, level)
    :param node: current node being visited
    :param level: level of the current node
    :return: None
    """
    if not node:
        return

    euler_tour.append((node.val, level))
    tour(euler_tour, node.left, level + 1)
    tour(euler_tour, node.right, level + 1)
    euler_tour.append((node.val, level))

def map_indices(indices, euler_tour):
    """
    This function maps node values to their indices in the Euler tour.
    :param indices: dictionary that stores node values as keys and a list of indices as values
    :param euler_tour: list that stores the Euler tour (node value, level)
    :return: None
    """
    for i, item in enumerate(euler_tour):
        indices[item[0]] = indices.get(item[0], []) + [i]

def map_prefix_suffix(prefix_max, suffix_max, euler_tour):
    """
    This function creates prefix and suffix maximum arrays based on the levels in the Euler tour.
    :param prefix_max: list that stores the maximum level from the start to each index
    :param suffix_max: list that stores the maximum level from each index to the end
    :param euler_tour: list that stores the Euler tour (node value, level)
    :return: None
    """
    max_ind = len(euler_tour) - 1
    for i, (_, level) in enumerate(euler_tour):
        prefix_max[i] = max(prefix_max[i - 1], level)

        _, suffix_level = euler_tour[max_ind - i]
        suffix_max[max_ind - i] = max(suffix_max[max_ind - i + 1], suffix_level)

def give_answer(queries, indices, prefix_max, suffix_max):
    """
    This function calculates the answers for the queries.
    :param queries: list of queries (node values)
    :param indices: dictionary that maps node values to their indices in the Euler tour
    :param prefix_max: list that stores the maximum level from the start to each index
    :param suffix_max: list that stores the maximum level from each index to the end
    :return: list of answers for the queries
    """
    return_answer = []
    for query in queries:
        start, end = indices[query]
        # this includes possibility of list spillover
        return_answer += [max(prefix_max[start - 1], suffix_max[end + 1])]
    return return_answer

class Solution(object):
    def treeQueries(self, root, queries):
        """
        :type root: Optional[TreeNode]
        :type queries: List[int]
        :rtype: List[int]
        """
        euler_tour = []
        indices = {}    
        
        tour(euler_tour, root, 0)

        map_indices(indices, euler_tour)

        prefix_max = [0 for i in range(len(euler_tour) + 1)]
        suffix_max = [0 for i in range(len(euler_tour) + 1)]

        map_prefix_suffix(prefix_max, suffix_max, euler_tour)

        return give_answer(queries, indices, prefix_max, suffix_max)

68706