Java Solution with comments
Complexity\n- Time complexity:\n Add your time complexity here, e.g. O(n) \nTime complexity of preprocessing: O(n * log(n))\nTime complexity of each query: O(lo
# Complexity\n- Time complexity:\n<!-- Add your time complexity here, e.g. $$O(n)$$ -->\nTime complexity of preprocessing: $$O(n * log(n))$$\nTime complexity of each query: $$O(log(n))$$\nTotal time complexity: $$O(n*log(n) + q*log(n))$$\n\n- Space complexity:\n<!-- Add your space complexity here, e.g. $$O(n)$$ -->\n$$O(n)$$\n\n# Code\n```\n/**\n * Definition for a binary tree node.\n * public class TreeNode {\n *     int val;\n *     TreeNode left;\n *     TreeNode right;\n *     TreeNode() {}\n *     TreeNode(int val) { this.val = val; }\n *     TreeNode(int val, TreeNode left, TreeNode right) {\n *         this.val = val;\n *         this.left = left;\n *         this.right = right;\n *     }\n * }\n */\nclass Solution {\n\n    int dfs(TreeNode root, Map<Integer, int[]> heights, int level) {\n        if(root == null) return 0;\n        heights.put(root.val, new int[] {1 + Math.max(dfs(root.left, heights, level + 1), dfs(root.right, heights, level + 1)), level});\n        return heights.get(root.val)[0];\n    }\n\n    public int[] treeQueries(TreeNode root, int[] queries) {\n        // map for storing height and level of each node\n        Map<Integer, int[]> heights = new HashMap<>();\n        // map for storing heights at each level\n        Map<Integer, PriorityQueue<Integer>> levelOrderHeights = new HashMap<>();\n\n        // dfs to calculate the height and level of each node\n        dfs(root, heights, 0);\n\n        int rootHeight = heights.get(root.val)[0];\n        for(int i = 0; i < heights.get(root.val)[0]; ++i) levelOrderHeights.put(i, new PriorityQueue<>((a, b) -> Integer.compare(b, a)));\n\n        // BFS to calculate heights and each level\n        Queue<TreeNode> q = new ArrayDeque<>();\n        q.add(root);\n        int level = 0;\n        while(!q.isEmpty()) {\n            int size = q.size();\n            while(size -- != 0) {\n                TreeNode node = q.poll();\n                levelOrderHeights.get(level).add(heights.get(node.val)[0]);\n                if(node.left != null) q.add(node.left);\n                if(node.right != null) q.add(node.right);\n            }\n            level ++;\n        }\n\n        int ans[] = new int[queries.length];\n        int i = 0;\n        for(int query: queries) {\n            int height = heights.get(query)[0];\n            int curlevel = heights.get(query)[1];\n            PriorityQueue<Integer> curheights = levelOrderHeights.get(curlevel);\n            \n            // if height of the deleted node is not the maximum at that level, then it will have no impact on the root height\n            if(height != curheights.peek()) ans[i++] = rootHeight - 1;\n           \n            // if it is the only node at that level, means height of the root will get reduced by height of the node subtree\n            else if(curheights.size() == 1) ans[i++] = rootHeight - height - 1;\n\n            // if deleted node has the max height at that level then the height of the root get reduced by the difference of max and second max height at that level\n            else {\n                int curHeight = curheights.poll();\n                int res = rootHeight - curHeight + curheights.peek();\n                curheights.add(curHeight);\n                ans[i++] = res - 1;\n            }\n        }\n        return ans;\n    }\n}\n```
['Java']