You learned the rerooting technique: compute answers for all possible roots in time using two DFS passes instead of brute force. Down pass computes subtree answers down[v] for each node. Up pass computes outside contributions up[v] using parent and sibling information.
Combine them: answer[v] = combine(down[v], up[v]). You solved and using rerooting. The pattern applies to any tree DP problem where you need answers for all possible roots. When you see "for each node as root", think rerooting.
Space complexity is for the data structures used.