the rerooting technique
Ordinary tree DP roots the tree once and computes, for each node, an answer about the subtree below it. But many questions ask for an answer at every node as if THAT node were the root — for example, for each node, the sum of distances to all other nodes, or the height of the tree if you hang it from that node. Re-running a full O(n) tree DP separately from each of the n roots would cost O(n^2). The rerooting technique gets the answer for all n roots in total O(n), by computing one rooted pass and then sliding the root from a node to its neighbour cheaply.
It works in two passes. First, a normal post-order DFS from an arbitrary root r fills 'down[v]', the contribution of v's subtree (as in plain tree DP). Second, a pre-order DFS pushes information back down: for each node v we compute 'up[v]', the contribution of everything OUTSIDE v's subtree, i.e. the part of the tree reached by going up through v's parent. The full answer for node v is then a combination of down[v] and up[v] — the whole tree seen from v. The trick is computing up[child] from up[parent] and the parent's other children efficiently: when you move the root across the edge (parent, child), the child gains the parent's side as new 'outside' and loses itself from the parent's downward sum. To do this in constant time per edge you often precompute prefix and suffix combinations of a node's children so you can exclude any one child quickly.
Both passes touch each edge a constant number of times, so the whole thing is O(n) — an n-fold speed-up over re-rooting from scratch. It is the standard tool whenever a problem says 'for every vertex, compute X where X depends on the rest of the tree'. The honest caveat is that rerooting needs the combine operation to support removing or excluding one child's contribution (so you can re-form the parent's value without the child you are moving into); operations that are not easily invertible (like a plain max where you must drop the maximizing child) need the prefix/suffix or other exclusion trick rather than naive subtraction.
Sum of distances from every node. First pass: down[v] = subtree size and the distance sum within v's subtree. Reroot across edge (u, v): the new answer ans[v] = ans[u] - (size[v]) + (n - size[v]), because the size[v] nodes get one step closer and the other n - size[v] nodes get one step farther. One add and subtract per edge gives all n answers in O(n).
Slide the root along one edge and update in O(1) instead of recomputing from scratch.
Rerooting is for 'answer at every node' questions; if you only need the answer for one fixed root, a single tree DP already suffices and rerooting is unnecessary overhead.