<p>Given the <code>root</code> of a binary tree, replace the value of each node in the tree with the <strong>sum of all its cousins&#39; values</strong>.</p>

<p>Two nodes of a binary tree are <strong>cousins</strong> if they have the same depth with different parents.</p>

<p>Return <em>the </em><code>root</code><em> of the modified tree</em>.</p>

<p><strong>Note</strong> that the depth of a node is the number of edges in the path from the root node to it.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2023/01/11/example11.png" style="width: 571px; height: 151px;" />
<pre>
<strong>Input:</strong> root = [5,4,9,1,10,null,7]
<strong>Output:</strong> [0,0,0,7,7,null,11]
<strong>Explanation:</strong> The diagram above shows the initial binary tree and the binary tree after changing the value of each node.
- Node with value 5 does not have any cousins so its sum is 0.
- Node with value 4 does not have any cousins so its sum is 0.
- Node with value 9 does not have any cousins so its sum is 0.
- Node with value 1 has a cousin with value 7 so its sum is 7.
- Node with value 10 has a cousin with value 7 so its sum is 7.
- Node with value 7 has cousins with values 1 and 10 so its sum is 11.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2023/01/11/diagram33.png" style="width: 481px; height: 91px;" />
<pre>
<strong>Input:</strong> root = [3,1,2]
<strong>Output:</strong> [0,0,0]
<strong>Explanation:</strong> The diagram above shows the initial binary tree and the binary tree after changing the value of each node.
- Node with value 3 does not have any cousins so its sum is 0.
- Node with value 1 does not have any cousins so its sum is 0.
- Node with value 2 does not have any cousins so its sum is 0.
</pre>

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

<ul>
	<li>The number of nodes in the tree is in the range <code>[1, 10<sup>5</sup>]</code>.</li>
	<li><code>1 &lt;= Node.val &lt;= 10<sup>4</sup></code></li>
</ul>

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

from collections import deque
import copy

class Solution:
    def replaceValueInTree(self, root):
        memo_parent = {}
        memo_parent[root] = None

        memo_depth = {}
        memo_depth[root] = 0

        self.inorder_traversal(root, memo_depth, memo_parent)

        level_order_nodes = []
        self.level_order_traversal(root, level_order_nodes)

        memo_parent_copy = {}
        for level_nodes in level_order_nodes:
            sum_level_nodes_val = sum([n.val for n in level_nodes])
            new_node_vals = []
            for node in level_nodes:
                new_node_vals.append(sum_level_nodes_val - self.sum_sibling_node_vals(node, memo_parent))
            for i in range(0, len(level_nodes)):
                level_nodes[i].val = new_node_vals[i]
        
        return root
    
    def sum_sibling_node_vals(self, node, memo_parent):
        if (memo_parent[node] is None):
            sum_sibling_nodes_val = node.val
        else:
            sum_sibling_nodes_val = 0
            if (memo_parent[node].left is not None):
                sum_sibling_nodes_val += memo_parent[node].left.val
            if (memo_parent[node].right is not None):
                sum_sibling_nodes_val += memo_parent[node].right.val
        
        return sum_sibling_nodes_val

    def inorder_traversal(self, node, memo_depth, memo_parent):
        if (node is None):
            return
        else:
            if (node.left is not None):
                memo_depth[node.left] = memo_depth[node] + 1
                memo_parent[node.left] = node
                self.inorder_traversal(node.left, memo_depth, memo_parent)

            if (node.right is not None):
                memo_depth[node.right] = memo_depth[node] + 1
                memo_parent[node.right] = node
                self.inorder_traversal(node.right, memo_depth, memo_parent)


    def level_order_traversal(self, node, level_order_nodes):
        queue = deque()
        if (node is not None):
            queue.append([node])
            level_order_nodes.append([node])
            while (len(queue) > 0):
                node_list = queue.popleft()
                level_nodes = deque()
                for n in node_list:
                    if (n.left is not None):
                        level_nodes.append(n.left)
                    if (n.right is not None):
                        level_nodes.append(n.right)
                
                if (len(level_nodes) > 0):
                    queue.append(level_nodes)
                    
                    level_order_nodes.append(level_nodes)
753