Split into independent halves, recurse, and handle what crosses the split. The combine step is where the work and the cleverness live. Its cost sets the total: combine gives , combine gives .

Template

ll solve(int l, int r) {                     // [l, r)
    if (r - l == 1) return base(l);
    int m = (l + r) / 2;
    ll res = solve(l, m) + solve(m, r);
    res += crossing(l, m, r);                // objects with one part in each half
    return res;
}

Recursion depth is , so it’s safe. Allocate merge buffers once, globally.

Counting pairs across the middle

Every pair is “crossing” at exactly one level of the recursion, the one where and separate. With both halves sorted (merge sort order), crossing pairs are usually counted with two pointers.

ProblemCrossing step
inversions; pairs with two pointers during the merge
pairs with sorted halves, two pointers
subarrays with sum in sorted prefix sums of each half
closest pair of pointsstrip of width sorted by , at most 7 neighbours each
3D dominance, offline 2D updatesCDQ

Subarrays crossing the middle

For “count / optimise over all subarrays of ”, the subarrays with split into a suffix of the left half and a prefix of the right half. Compute an aggregate for each left start (scanning left from ) and each right end (scanning right from ), then combine them with sorting, two pointers or a data structure. Example: count subarrays where length (permutation subarrays): split by whether the max and the min fall on the left or the right; each case is linear with two pointers. total.

Divide at the maximum (unbalanced D&C): for “subarrays whose maximum is ”, the split point is the maximum, not the middle. Iterate over the shorter side and query the longer side with a precomputed structure. Since each element is on the shorter side times (like small-to-large), the total is times the query cost. This is a traversal of the Cartesian tree.

Offline range queries by D&C

Answer queries for an operation that’s hard to combine (knapsack over a range, a “best subsequence” DP, path counts in a grid strip): recurse on with mid . Queries with are answered at this node; the others go to the side that contains them. At the node, compute for every the DP of (a suffix DP growing leftwards), and for every the DP of , then combine the two DP states for each query.

  • Range 0/1 knapsack queries “best value of with capacity ”: .
  • Grid reachability queries “can reach moving right/down”: split rows at the middle, bitset of reachable middle-row cells from each source and to each target, .
  • It’s the disjoint-sparse-table idea applied to arbitrary DP states (Disjoint Sparse Table).

Divide and conquer on other axes

  • On time (segment tree over the query timeline): each element’s lifetime is tree nodes; DFS the tree with a rollback structure. That’s offline dynamic connectivity, bipartiteness and XOR basis under deletions (Dynamic Connectivity).
  • On values (“overall binary search”): recurse on the answer range with the queries whose answer lies there, applying the updates with values in to a BIT to split the queries. It’s parallel binary search written recursively, and it handles range -th smallest with updates in .
  • On a tree: centroid decomposition gives depth , and every path passes through exactly one centroid in its component (Centroid Decomposition).
  • On DP layers: monotone optimum splits, per layer (D&C Optimization).
  • On the plane: closest pair, Delaunay triangulation, convex hull by merging.

Classic D&C algorithms

AlgorithmRecurrenceTime
merge sort, inversion count
closest pair of points (presorted by via merging)
Karatsuba multiplication
Strassen
FFT
median of medians
maximum subarray (as a D&C) with a 4-value summary
skyline / union of rectangles in 1Dmerge two skylines
polynomial multipoint evaluationproduct tree, remainder tree

This is the master theorem (restricted to polynomial , which covers every row above; Complexity and Analysis states the fully general version and the non-polynomial Akra–Bazzi extension).