Commented DFS Approach
Code

# Code
```python3 []
from collections import defaultdict
from typing import List
from heapq import nlargest, nsmallest

class Solution:
    def placedCoins(self, edges: List[List[int]], cost: List[int]) -> List[int]:
        n = len(cost)
        ans = [1] * n  # Default every node to receive 1 coin
        adj = defaultdict(list)

        # Construct an undirected graph
        for f, t in edges:
            adj[f].append(t)
            adj[t].append(f)  # Ensure bidirectional edges

        def dfs(node, parent):
            size = 1
            max_vals = [cost[node]]  # Track top 3 max values
            min_vals = [cost[node]]  # Track top 2 min values

            for neighbor in adj[node]:
                if neighbor == parent:  # Avoid revisiting the parent
                    continue

                small, large, sub_size = dfs(neighbor, node)
                size += sub_size
                max_vals.extend(large)
                min_vals.extend(small)

                # Keep only the top 3 max values and top 2 min values
                max_vals = nlargest(3, max_vals)
                min_vals = nsmallest(2, min_vals)

            # Assign coin value based on subtree size
            if size >= 3:
                prod1 = max_vals[0] * max_vals[1] * max_vals[2] if len(max_vals) == 3 else float('-inf')
                prod2 = min_vals[0] * min_vals[1] * max_vals[0] if len(min_vals) == 2 else float('-inf')

                ans[node] = max(0, prod1, prod2)  # If all are negative, store 0

            return min_vals, max_vals, size

        dfs(0, -1)
        return ans

```
['Python3']