DP · trees · graphs · 135 problems · 59 core

Hard Drill

One section per pattern: how to spot it, the key idea, the usual bug, then problems ordered easy to hard. Ratings are Codeforces ratings or the LeetCode contest rating (~ marks an estimate).

0
Saved in this browser only

5-day plan (★ core problems only)

  1. Day 1: interval DP and bitmask DP
  2. Day 2: digit DP, DP optimisations, the contribution technique
  3. Day 3: tree DP and rerooting, binary lifting, Euler tour
  4. Day 4: state-space shortest paths, offline DSU, bridges
  5. Day 5: functional graphs and Euler paths, then a timed mock: 3 unseen problems in 90 minutes
Ideas that make "non-intuitive" problems click (13)
  • Think about the last move. When splitting a range by the first action leaves the subproblems dependent on each other, choose the element handled last instead. Its neighbours are then fixed. (LC 312, 1039, 546)
  • Run time backwards. Deletions break DSU, but insertions don't. Apply all removals first, then add elements back in reverse order. (LC 803, offline queries)
  • Count the complement. Count the numbers with all-distinct digits, or the bad arrangements, and subtract from the total. (LC 1012)
  • Contribution counting. Sum over each element the number of subarrays, paths or subtrees it contributes to, instead of enumerating the answers. (LC 907, 828, 2262, 834)
  • The answer is tiny. Some answers can only be 0, 1 or 2. Prove the bound, then check each case. (LC 1568, CF 321C)
  • Sort to make it a DP. Sorting by end time or by width turns the problem into LIS or weighted interval scheduling. (LC 354, 1235, 1751)
  • Binary search the answer. "Maximise the minimum" or "minimise the maximum" usually means binary searching the threshold and checking it with BFS or DSU. (LC 778, 2812)
  • Put the state in the node. Keys held, eliminations left, stops used or edges doubled all go into the node: the graph becomes (vertex, extra state). (LC 1293, 864, 787, CF 1473E)
  • Reroot in O(1) per edge. Solve for root 0, then work out what changes when the root moves across one edge. (LC 834, 2858, 2581)
  • Process by value with DSU. Activate nodes or edges in sorted order and answer each query when its threshold is reached. (LC 2421, 1697, CF 1213G)
  • Parity and XOR invariants. XOR along a path cancels everywhere except the endpoints, so the tree structure often stops mattering. (LC 3068, CF 776D)
  • Huge n, small transition. With n up to 1e18 or k up to 1e10, use matrix exponentiation or binary lifting. (CF 1117D, LC 2836)
  • Draws break memoisation. When a game has cycles, recursive memoisation gives wrong answers. Run a retrograde BFS outward from the terminal states. (LC 913)

DP

Interval DP

How to spot it
Merge, burst or remove things in a sequence, where the cost depends on what is adjacent at that moment. n ≤ 500.
Key idea
dp[l][r] over a range. Split on the element handled last, or on the partner the left end gets merged with.
Usual bug
Loop by increasing length, not by l. Use half-open or closed ranges consistently. Pad the sequence with sentinels.
  1. Burst Balloons
    LC 312★ core
    Hint
    Choose the balloon k that bursts last in (l, r). At that point its neighbours are l-1 and r+1, so dp[l][r] = max over k of dp[l][k-1] + dp[k+1][r] + a[l-1]·a[k]·a[r+1].
    ~2100
  2. Minimum Score Triangulation of Polygon
    LC 1039
    Hint
    Edge (i, j) belongs to exactly one triangle (i, k, j). dp[i][j] = min over k of dp[i][k] + dp[k][j] + v[i]v[k]v[j].
    ~1900
  3. Minimum Cost to Cut a Stick
    LC 1547★ core
    Hint
    Add 0 and n to the cuts and sort them. Run the DP over cut indices. The cost of a segment is cuts[j] - cuts[i], whichever cut happens first.
    ~2100
  4. Strange Printer
    LC 664★ core
    Hint
    dp[l][r] = dp[l+1][r] + 1, or for any k with s[k] == s[l], merge s[l]'s stroke into s[k]'s: dp[l+1][k-1] + dp[k][r].
    ~2200
  5. Clear the String
    CF 1132F
    Hint
    Same structure as Strange Printer: delete s[l] alone, or save it for the same deletion as a later equal character k.
    ~2000
  6. Zuma
    CF 607B
    Hint
    dp[l][r] = min(1 + dp[l+1][r], 1 + dp[l+2][r] if c[l] == c[l+1], dp[l+1][k-1] + dp[k+1][r] for c[k] == c[l]). Gem l is removed together with gem k, wrapped around the middle.
    ~1900
  7. Minimum Cost to Merge Stones
    LC 1000
    Hint
    If (n-1) % (K-1) ≠ 0 the answer is -1. dp[l][r] is the cost of merging the range down as far as possible. Split at m in steps of K-1, and add the range sum when (r-l) % (K-1) == 0.
    ~2400
  8. Remove Boxes
    LC 546
    Hint
    Two dimensions aren't enough. Add a third: dp[l][r][k], where k boxes equal to box[l] are attached on the left. Either remove them now, or join them with a later equal box.
    ~2700

Bitmask DP & SOS

How to spot it
n ≤ 20 (or a small m with ≤ 2^m colours or skills). The problem asks you to assign, order or cover a set.
Key idea
dp[mask] or dp[mask][last]. popcount(mask) often stands in for an index you would otherwise store. SOS DP aggregates over submasks in O(2^n · n).
Usual bug
Enumerate submasks with s = (s-1) & mask, and handle s = 0 explicitly. Watch operator precedence: write (mask >> i) & 1 with brackets.
  1. Shortest Path Visiting All Nodes
    LC 847★ core
    Hint
    Multi-source BFS over (node, visited mask), starting from every node with mask = 1<<node.
    ~2000
  2. Minimum XOR Sum of Two Arrays
    LC 1879
    Hint
    dp[mask] means nums2 elements in mask are used. The next nums1 index is popcount(mask).
    ~2000
  3. Smallest Sufficient Team
    LC 1125★ core
    Hint
    Iterate over people; dp[mask | skills[p]] = min(dp[mask] + 1). Store a parent pointer instead of copying lists.
    ~2200
  4. Find the Shortest Superstring
    LC 943
    Hint
    Precompute pairwise overlaps. Then it's TSP: dp[mask][last] = max total overlap. Reconstruct the string from parent pointers.
    ~2400
  5. Parallel Courses II
    LC 1494★ core
    Hint
    Greedy topological order is wrong. dp[mask] = minimum semesters. avail = courses whose prerequisites are all in mask; try every submask of avail with size ≤ k (or all of avail if it fits).
    ~2600
  6. Maximum Students Taking Exam
    LC 1349
    Hint
    Row-by-row mask DP. cur must avoid broken seats and have no adjacent bits; it's compatible with prev if (cur<<1 & prev) and (cur>>1 & prev) are both 0.
    ~2400
  7. Maximum AND Sum of Array
    LC 2172
    Hint
    Each slot holds 2 numbers, so use 2·numSlots bits. The number being placed is popcount(mask).
    ~2400
  8. Compatible Numbers
    CF 165E
    Hint
    You need some b with a & b = 0, so b ⊆ ~a. SOS DP: best[mask] = any element that is a submask of mask.
    ~2200

Digit DP

How to spot it
"Count integers in [L, R] such that …" with R up to 1e18, or given as a string.
Key idea
f(R) - f(L-1). State (pos, tight, started, property), where the property is a sum, a mask or a count.
Usual bug
Leading zeros: a started flag. Memoise only when not tight, or include tight in the key. When L is a string, compute f(L) and check L itself.
  1. Numbers At Most N Given Digit Set
    LC 902
    Hint
    Shorter lengths contribute d^len for free. Then walk n's digits while tight.
    ~1900
  2. Number of Digit One
    LC 233★ core
    Hint
    Per position: split into high / cur / low and count how often this digit is 1. This is the contribution form of a digit DP.
    ~2000
  3. Count Special Integers
    LC 2376★ core
    Hint
    State (pos, used-digit mask, tight, started). Zeros before the number starts don't go into the mask.
    ~2100
  4. Numbers With Repeated Digits
    LC 1012
    Hint
    Count the complement: n minus the numbers ≤ n with all distinct digits.
    ~2200
  5. Count of Integers
    LC 2719★ core
    Hint
    dp(pos, digit sum, tight), with the sum capped at max_sum. The answer is f(num2) - f(num1) + [num1 itself is valid].
    ~2350
  6. Classy Numbers
    CF 1036C
    Hint
    State (pos, non-zero digits so far ≤ 3, tight).
    ~1900

Tree DP & rerooting

How to spot it
"For every node as root…", sums of distances, cover or guard problems, or cutting a tree into parts.
Key idea
Post-order DFS returning several states. For every-root answers, compute root 0, then a second DFS pushes the parent's answer down.
Usual bug
Recursion depth reaches 1e5 in Python (and can overflow the C++ stack too). Use an iterative DFS or an explicit order. Keep the 'down' and 'up' values separate.
  1. Choosing Capital for Treeland
    CF 219D
    Hint
    Store each edge in both directions: cost 0 along the original direction, 1 against it. Count the cost for root 0, then moving the root across an edge flips that edge's contribution.
    ~1700
  2. Maximum White Subtree
    CF 1324F
    Hint
    down[v] = a[v] + Σ max(0, down[child]). Then full[child] = down[child] + max(0, full[v] - max(0, down[child])).
    ~1800
  3. Tree with Maximum Cost
    CF 1092F
    Hint
    res[child] = res[v] + total - 2·sub[child], where sub is the subtree weight sum.
    ~1900
  4. Binary Tree Cameras
    LC 968★ core
    Hint
    Three states per node: no camera and uncovered, covered without a camera, has a camera. Equivalently, greedily put cameras on the parents of leaves.
    ~2100
  5. Sum of Distances in Tree
    LC 834★ core
    Hint
    ans[child] = ans[v] - size[child] + (n - size[child]). Moving the root one step brings size[child] nodes closer and pushes the rest further away.
    ~2200
  6. Minimum Edge Reversals So Every Node Is Reachable
    LC 2858
    Hint
    Same as Treeland: forward edge costs 0, reverse costs 1, then reroot.
    ~2300
  7. Count Number of Possible Root Nodes
    LC 2581
    Hint
    Count the correct guesses for root 0. Moving the root from u to v changes only the guesses (u, v) and (v, u).
    ~2200
  8. Longest Path With Different Adjacent Characters
    LC 2246★ core
    Hint
    At each node keep the two longest child chains whose character differs from the node's. The answer is 1 + best1 + best2.
    ~2100
  9. Create Components With Same Value
    LC 2440★ core
    Hint
    The number of components must divide the total. For each divisor, DFS returns the subtree sum, cuts when the sum equals the target and fails when it goes over.
    ~2400
  10. Difference Between Maximum and Minimum Price Sum
    LC 2538
    Hint
    The cost is a path sum minus one endpoint. For each node keep two values: the best chain down that includes its leaf, and the best that excludes it. Combine at each node.
    ~2400
  11. Karen and Supermarket
    CF 815C
    Hint
    Tree knapsack: dp[v][k][coupon used?]. Merging children in order of size keeps the total at O(n²).
    ~2400

DP on DAGs

How to spot it
Longest or most-valuable path in a directed graph, or 'strictly increasing' moves on a grid.
Key idea
Topological order (Kahn's algorithm) carrying the DP values along. Strictly increasing moves are acyclic automatically.
Usual bug
Detect cycles: if Kahn's processes fewer than n nodes, return -1.
  1. Longest Increasing Path in a Matrix
    LC 329
    Hint
    DFS with memoisation. Strictly increasing moves can't cycle, so no visited set is needed.
    ~2000
  2. Parallel Courses III
    LC 2050
    Hint
    Longest path with node weights, computed in topological order.
    ~2100
  3. Largest Color Value in a Directed Graph
    LC 1857★ core
    Hint
    Kahn's algorithm with dp[node][colour] = maximum count of that colour on any path ending at node. Return -1 if there's a cycle.
    ~2300

Extra-state DP (state machines)

How to spot it
Limited transactions, cooldowns, a run-length encoding, constraints like 'at most k in a row'.
Key idea
Add one small dimension for the part of the history that matters: holding or not, the current run length, absences so far.
Usual bug
Index transactions by buys or sells, not both. Encoded run length grows in steps at 1, 9 and 99.
  1. Best Time to Buy and Sell Stock IV
    LC 188
    Hint
    dp[j][holding]. If k ≥ n/2 the limit doesn't bind, so treat it as unlimited.
    ~2000
  2. Student Attendance Record II
    LC 552★ core
    Hint
    States are (absences 0–1, trailing lates 0–2): 6 states, O(n). For huge n, use matrix exponentiation.
    ~2300
  3. String Compression II
    LC 1531
    Hint
    dp[i][k]: either delete s[i], or keep s[i] as the start of a run and scan ahead, deleting the characters that differ, while tracking the run length.
    ~2600

Probability & expectation

How to spot it
"Probability that…" or "expected number of…".
Key idea
dp over steps or values. When the probabilities are uniform over a window, keep a sliding window sum.
Usual bug
Add up the absorbing states correctly. Floating-point probabilities converge, so you can cut off at large n.
  1. Ilya and Escalator
    CF 518D
    Hint
    dp[t][j] = probability that j people are on the escalator after t seconds.
    ~1700
  2. Knight Probability in Chessboard
    LC 688
    Hint
    Spread probability over k steps; each move gets 1/8.
    ~1800
  3. Soup Servings
    LC 808
    Hint
    Divide by 25. For n ≥ about 4800 the answer is 1 to within the allowed error.
    ~2000
  4. New 21 Game
    LC 837★ core
    Hint
    dp[x] = (sum of dp[x-maxPts .. x-1] restricted to values < k) / maxPts, kept as a sliding window sum. The answer is Σ dp[k..n].
    ~2350

DP optimisations

How to spot it
The DP is correct but O(n²) or O(nk) is too slow.
Key idea
Max of a sliding window → monotonic deque. A sum over a range → prefix sums. Next compatible index → binary search. Linear cost in j → convex hull trick. Monotone optimal split → divide and conquer.
Usual bug
In the deque, pop expired indices from the front before reading the value. Keep prefix-sum indices off by one consistently.
  1. Find the Longest Valid Obstacle Course at Each Position
    LC 1964
    Hint
    Non-decreasing LIS: bisect_right on the tails array; the answer at i is the insert position + 1.
    ~1900
  2. Jump Game VI
    LC 1696★ core
    Hint
    dp[i] = nums[i] + max(dp[i-k .. i-1]), taken from a monotonic deque.
    ~1950
  3. Maximum Profit in Job Scheduling
    LC 1235★ core
    Hint
    Sort by end time. dp[i] = max(dp[i-1], profit[i] + dp[last job ending ≤ start[i]]), found by binary search.
    ~2000
  4. Maximum Number of Events That Can Be Attended II
    LC 1751
    Hint
    dp[i][k], with the next index found by binary search.
    ~2000
  5. Constrained Subsequence Sum
    LC 1425
    Hint
    Like Jump Game VI, but take max(0, window max).
    ~2050
  6. Russian Doll Envelopes
    LC 354★ core
    Hint
    Sort by width ascending and height descending, so equal widths can't chain, then run strict LIS on the heights.
    ~2100
  7. Shortest Subarray with Sum at Least K
    LC 862★ core
    Hint
    Negative values rule out a sliding window. Keep prefix indices in a deque with increasing values; pop from the front while P[i] - P[front] ≥ k.
    ~2300
  8. K Inverse Pairs Array
    LC 629★ core
    Hint
    dp[n][k] = dp[n][k-1] + dp[n-1][k] - dp[n-1][k-n] (a prefix-sum telescope).
    ~2300
  9. Kalila and Dimna in the Logging Industry
    CF 319C
    Hint
    dp[i] = min over j of dp[j] + b[j]·a[i]. The slopes b decrease and the queries a increase, so a monotone convex hull trick deque works.
    ~2100
  10. Yet Another Minimization Problem
    CF 868F
    Hint
    The optimal split point is monotone, so use divide-and-conquer DP. Compute cost(l, r) with Mo-style moving pointers.
    ~2500

Counting & combinatorics

How to spot it
"Number of ways mod 1e9+7", permutations with constraints, orderings.
Key idea
Insert elements one at a time, smallest or largest first. Think about where the newest element can go.
Usual bug
Take the mod after every multiplication, and add the mod before taking a subtraction mod. Precompute factorials and inverse factorials.
  1. Number of Ways to Rearrange Sticks With K Sticks Visible
    LC 1866
    Hint
    Place the shortest stick last in reasoning: it's visible only if it comes first. dp[n][k] = dp[n-1][k-1] + (n-1)·dp[n-1][k].
    ~2100
  2. Number of Ways to Reorder Array to Get Same BST
    LC 1569★ core
    Hint
    ways(T) = C(|L|+|R|, |L|) · ways(L) · ways(R). Subtract 1 for the original order.
    ~2300
  3. Number of Music Playlists
    LC 920
    Hint
    dp[i][j] = dp[i-1][j-1]·(n-j+1) + dp[i-1][j]·max(j-k, 0).
    ~2400
  4. Valid Permutations for DI Sequence
    LC 903
    Hint
    dp[i][j] = number of ways where the last element has relative rank j among the first i+1. Prefix sums over j.
    ~2400
  5. Count Ways to Build Rooms in an Ant Colony
    LC 1916
    Hint
    The number of topological orders of a rooted tree is n! / ∏ size(v).
    ~2500

String DP

How to spot it
Two strings matched against each other, palindromes, distinct subsequences.
Key idea
dp[i][j] over prefixes. For distinct counts, subtract the value from the previous occurrence of the same character.
Usual bug
Empty-string base cases. '*' in a regex applies to the previous character. Counts overflow without a mod.
  1. Distinct Subsequences
    LC 115
    Hint
    dp[i][j] = dp[i-1][j] + (s[i] == t[j]) · dp[i-1][j-1]. Iterate j backwards to use 1D.
    ~1900
  2. Palindrome Partitioning II
    LC 132★ core
    Hint
    Expand around each centre and update cut[r+1] = min(cut[r+1], cut[l] + 1). O(n²) with no palindrome table.
    ~2000
  3. Distinct Subsequences II
    LC 940★ core
    Hint
    total' = 2·total - (count just before the previous occurrence of this character).
    ~2000
  4. Regular Expression Matching
    LC 10
    Hint
    For 'x*': use it zero times (dp[i][j-2]), or once more if x matches (dp[i-1][j]).
    ~2000
  5. Count Different Palindromic Subsequences
    LC 730
    Hint
    Per character c: look at the first and last occurrence of c inside [l, r]. If there's none, one, or more than one, the recurrence differs. Don't double-count.
    ~2600

Game DP

How to spot it
Two players play optimally; who wins, or what is the score difference.
Key idea
dp = best score difference for the player to move. If the game graph has cycles, run a retrograde BFS from terminal states using out-degree counters.
Usual bug
Memoising a game that can cycle gives wrong answers because draws exist.
  1. Stone Game III
    LC 1406
    Hint
    dp[i] = max over x in 1..3 of (sum of the x stones taken - dp[i+x]).
    ~1800
  2. Stone Game II
    LC 1140
    Hint
    dp[i][M] = suffix[i] - min over x in 1..2M of dp[i+x][max(M, x)].
    ~2000
  3. Cat and Mouse
    LC 913★ core
    Hint
    State (mouse, cat, turn). Seed the known results (mouse at the hole, cat catches mouse) and propagate backwards: a state is a loss once all its moves lead to wins for the opponent. Whatever is left is a draw.
    ~2600

Grid & profile DP

How to spot it
Colouring or filling a grid with a small width (m ≤ 5), or two paths at once.
Key idea
Enumerate the valid row or column patterns, then build a transition matrix between them. For two walkers, move both together with the step index t shared.
Usual bug
Don't count a cell twice when both walkers stand on it. Precompute which patterns are compatible.
  1. Cherry Pickup II
    LC 1463
    Hint
    dp[row][c1][c2].
    ~1950
  2. Painting a Grid With Three Different Colors
    LC 1931★ core
    Hint
    m ≤ 5, so there are at most 48 valid columns. Build the compatibility matrix and run n steps.
    ~2200
  3. Cherry Pickup
    LC 741★ core
    Hint
    Going there and back equals two forward paths. dp[t][r1][r2], with c = t - r.
    ~2300
  4. Maximize Grid Happiness
    LC 1659
    Hint
    Broken profile: process one cell at a time with a base-3 code of the last n cells, plus the number of introverts and extroverts left.
    ~2650

Contribution technique

How to spot it
A sum over all subarrays or substrings of some function.
Key idea
For each element, count how many subarrays it decides (is the minimum of, is unique in, adds to).
Usual bug
Ties: use strict comparison on one side and non-strict on the other, or equal elements get counted twice.
  1. Sum of Subarray Minimums
    LC 907★ core
    Hint
    Monotonic stack gives left[i] and right[i]. The contribution is a[i] · left · right.
    ~1950
  2. Total Appeal of A String
    LC 2262
    Hint
    Each occurrence adds (i - last[c]) · (n - i).
    ~2000
  3. Count Unique Characters of All Substrings of a Given String
    LC 828★ core
    Hint
    Each occurrence adds (i - prev) · (next - i).
    ~2050

Matrix exponentiation

How to spot it
A linear recurrence with n up to 1e18.
Key idea
Build the companion matrix and raise it to the power n in O(m³ log n).
Usual bug
Overflow in the multiplication; use 64-bit and take the mod inside the loop.
  1. Magic Gems
    CF 1117D★ core
    Hint
    f(n) = f(n-1) + f(n-M), with an M×M companion matrix.
    ~2100

Trees

Binary lifting & LCA

How to spot it
k-th ancestor, path queries, distance between nodes, many queries.
Key idea
up[j][v] = up[j-1][up[j-1][v]]. Compute path aggregates from prefix values: val(u) + val(v) - 2·val(lca).
Usual bug
Lift to equal depth before lifting both nodes together. Make the root's parent the root itself (or -1, checked).
  1. Tree Queries
    CF 1328E★ core
    Hint
    Replace each query vertex with its parent, then check they all lie on the root path to the deepest one, using tin and tout.
    ~1900
  2. Kth Ancestor of a Tree Node
    LC 1483
    Hint
    A binary lifting table, about 17 levels.
    ~2100
  3. Minimum Edge Weight Equilibrium Queries in a Tree
    LC 2846★ core
    Hint
    Keep a count of each weight 1..26 from the root to every node. Path count = c[u] + c[v] - 2·c[lca]. Answer = path length - largest count.
    ~2550

Euler tour + segment tree / BIT

How to spot it
Subtree updates or queries.
Key idea
A subtree is the contiguous range [tin, tout] in DFS order, so subtree operations become range operations.
Usual bug
Pick one convention for tout (inclusive or exclusive) and use it everywhere.
  1. Vasya and a Tree
    CF 1076E
    Hint
    Offline DFS with a difference array indexed by depth: add on entry, undo on exit.
    ~1900
  2. New Year Tree
    CF 620E★ core
    Hint
    A segment tree over the Euler tour storing a 60-bit colour mask, with lazy assignment. Answer with popcount.
    ~2100
  3. Propagating tree
    CF 383C
    Hint
    Value signs alternate by depth parity. Use a BIT range update over the subtree, with the sign set by depth.
    ~2000

Small-to-large (DSU on tree)

How to spot it
Per-subtree counts of colours, depths or distinct values.
Key idea
Keep the heavy child's map and merge the smaller maps into it, for O(n log n) total.
Usual bug
Swap the pointers when merging; don't copy the maps.
  1. Tree Requests
    CF 570D
    Hint
    Bucket nodes by depth in tin order and binary search the subtree range. A palindrome is possible if the XOR of letter parities has at most 1 bit set.
    ~2200
  2. Lomsat gelral
    CF 600E★ core
    Hint
    Small-to-large on maps of colour counts, carrying (best frequency, sum of colours with it).
    ~2300

Centroid decomposition & HLD

How to spot it
Path or distance queries with updates, counting paths of length k.
Key idea
Centroid: each path goes through some centroid ancestor, giving log n levels. HLD: any path splits into O(log n) heavy chains on a segment tree.
Usual bug
Mark removed centroids. Recompute subtree sizes inside each component.
  1. Ciel the Commander
    CF 321C
    Hint
    Rank = depth in the centroid tree. It's always possible because the depth is at most log n ≤ 26.
    ~2100
  2. Water Tree
    CF 343D
    Hint
    Fill a subtree = range assign on the Euler tour. Empty the path to the root = HLD path assign.
    ~2100
  3. Xenia and Tree
    CF 342E★ core
    Hint
    For each centroid ancestor c of the painted node, best[c] = min(best[c], dist). A query takes the min of best[c] + dist(v, c).
    ~2400

Peeling leaves, diameter & centres

How to spot it
Minimum height, removing leaves, the tree's diameter or centre.
Key idea
Topological peeling from the leaves. Find the diameter with BFS twice. The centre is the middle of the diameter.
Usual bug
Handle n = 1 and n = 2 separately.
  1. Minimum Height Trees
    LC 310
    Hint
    Peel leaves layer by layer; the last 1 or 2 nodes left are the centres.
    ~1800
  2. Count Subtrees With Max Distance Between Cities
    LC 1617
    Hint
    n ≤ 15. Enumerate subsets, check each is connected, and take its diameter from Floyd-Warshall distances.
    ~2300
  3. Collect Coins in a Tree
    LC 2603★ core
    Hint
    Repeatedly remove leaves without coins, then strip 2 more layers of leaves. The answer is 2 · (edges remaining).
    ~2700

Binary tree tricks

How to spot it
Validating or rebuilding structure, answering per-node removal queries.
Key idea
Post-order returning a tuple. To answer 'remove a subtree' queries, precompute the best result outside each subtree.
Usual bug
Use ±inf sentinels for empty subtrees when checking BST bounds.
  1. Recover a Tree From Preorder Traversal
    LC 1028
    Hint
    Count the dashes to get the depth, then use a stack trimmed to that depth.
    ~1800
  2. Maximum Sum BST in Binary Tree
    LC 1373
    Hint
    Post-order returns (isBST, min, max, sum).
    ~1900
  3. Height of Binary Tree After Subtree Removal Queries
    LC 2458★ core
    Hint
    Two DFS passes: left-first and right-first, each carrying the maximum height reached so far before entering a node. The answer for a node combines what lies outside its subtree.
    ~2300

Tree XOR & edge removal

How to spot it
Remove 1 or 2 edges, or XOR operations along paths.
Key idea
Ancestor tests with tin/tout let you get a component's XOR in O(1). Path operations often reduce to parity at the endpoints.
Usual bug
When both removed edges lie on the same root path, the inner component's value is part of the outer one.
  1. Find the Maximum Sum of Node Values
    LC 3068★ core
    Hint
    XORing along a path toggles only its two endpoints, so you can toggle any even-size set of nodes. Greedy or DP on parity; the tree shape doesn't matter.
    ~2250
  2. Minimum Score After Removals on a Tree
    LC 2322
    Hint
    Precompute subtree XORs and tin/tout. Try all O(n²) pairs of edges, using the ancestor test to work out the three components.
    ~2400

Trie (bitwise)

How to spot it
Maximum XOR of pairs, queries with bounds, XOR on a tree path.
Key idea
A binary trie, walked greedily toward the opposite bit. Handle bounds offline by sorting queries, and tree paths by inserting on DFS entry and deleting on exit.
Usual bug
Fix the bit width (30 or 31). Deleting needs per-node counts.
  1. Vasiliy's Multiset
    CF 706D
    Hint
    A trie with counts supporting insert, delete and maximum XOR.
    ~1800
  2. Maximum XOR of Two Numbers in an Array
    LC 421
    Hint
    Greedy trie walk from the top bit.
    ~2000
  3. Maximum XOR With an Element From Array
    LC 1707★ core
    Hint
    Offline: sort the queries by m and insert numbers ≤ m as you go.
    ~2350
  4. Maximum Genetic Difference Query
    LC 1938
    Hint
    Offline DFS: insert a node on entry, answer the queries at that node, delete it on exit.
    ~2500

Graphs

0-1 BFS & state-space Dijkstra

How to spot it
Edge costs of 0 or 1, limited stops or eliminations, a second-best path, counting shortest paths.
Key idea
A deque for 0/1 weights. Put the constraint into the node: (v, stops), (r, c, k), (v, layer).
Usual bug
Skip stale heap entries (if d > dist[v]: continue). Use 64-bit distances. Copy the array each round in Bellman-Ford with k rounds.
  1. Cheapest Flights Within K Stops
    LC 787
    Hint
    Bellman-Ford for k+1 rounds, copying the distance array each round.
    ~1800
  2. Shortest Path in a Grid with Obstacles Elimination
    LC 1293
    Hint
    BFS over (r, c, eliminations left). If k ≥ m + n - 2, return the Manhattan distance.
    ~1950
  3. Minimum Cost to Make at Least One Valid Path in a Grid
    LC 1368★ core
    Hint
    0-1 BFS: following a cell's arrow costs 0, any other direction costs 1.
    ~2100
  4. Number of Ways to Arrive at Destination
    LC 1976★ core
    Hint
    Dijkstra that also counts ways: on a tie, ways[v] += ways[u]; on an improvement, reset.
    ~2100
  5. Minimum Obstacle Removal to Reach Corner
    LC 2290
    Hint
    0-1 BFS where a cell's weight is whether it's an obstacle.
    ~2150
  6. Second Minimum Time to Reach Destination
    LC 2045★ core
    Hint
    BFS keeping the first two distinct arrival distances per node, then simulate the red/green traffic signals for that number of edges.
    ~2200
  7. Reachable Nodes In Subdivided Graph
    LC 882
    Hint
    Dijkstra on the original nodes. Edge (u, v, cnt) adds min(cnt, max(0, M - d[u]) + max(0, M - d[v])).
    ~2300
  8. Minimum Time to Visit a Cell In a Grid
    LC 2577★ core
    Hint
    If both neighbours of the start are blocked, return -1. Otherwise you can wait by stepping back and forth, so the arrival time is raised to the cell's time, adjusted for parity.
    ~2400
  9. Minimum Path
    CF 1473E★ core
    Hint
    sum - max + min equals using one edge twice and another edge zero times. Run Dijkstra over (v, doubled used?, zeroed used?), with 4 layers.
    ~2400

Multi-source & reverse-graph shortest paths

How to spot it
Two sources meeting at a target, the nearest of many sources, all-to-one queries.
Key idea
Run Dijkstra on the reversed graph from the target. A virtual super-source connects to every source.
Usual bug
Build the reversed adjacency separately; don't reuse the forward one.
  1. Find the Safest Path in a Grid
    LC 2812★ core
    Hint
    Multi-source BFS from the thieves gives a safety grid. Then find the max-min path with a max-heap Dijkstra or binary search + BFS.
    ~2150
  2. Minimum Weighted Subgraph With the Required Paths
    LC 2203★ core
    Hint
    Three Dijkstras: from src1, from src2, and from dest on the reversed graph. Answer = min over meeting node x of the three distances summed.
    ~2350

Bridges, articulation points, SCC, 2-SAT

How to spot it
Critical edges, disconnecting a graph, orienting edges, mutual reachability, boolean constraints.
Key idea
Tarjan low-link values: tree edge (u, v) is a bridge if low[v] > tin[u]. SCC by Tarjan or Kosaraju. 2-SAT or parity DSU for pairwise boolean constraints.
Usual bug
Skip only the parent edge itself, not every edge to the parent (multi-edges). Use an iterative DFS in Python.
  1. Checkposts
    CF 427C
    Hint
    Within each SCC, take the minimum cost and count how many nodes have it; multiply the counts.
    ~1700
  2. Critical Connections in a Network
    LC 1192★ core
    Hint
    Tarjan bridges.
    ~2100
  3. Bertown roads
    CF 118E
    Hint
    Possible if and only if there are no bridges. Orient tree edges downward and back edges upward.
    ~2000
  4. The Door Problem
    CF 776D
    Hint
    Each door is controlled by exactly 2 switches, which gives an XOR constraint. Use a parity DSU, or 2-colouring.
    ~2000
  5. Minimum Number of Days to Disconnect Island
    LC 1568★ core
    Hint
    The answer is always 0, 1 or 2. Check whether it's already disconnected, then try removing each cell.
    ~2200

Offline DSU & processing by value

How to spot it
Queries with thresholds ('using edges with weight < limit'), paths where every node is ≤ the endpoints.
Key idea
Sort the edges and the queries (or the nodes by value) and sweep, unioning as you go.
Usual bug
Keep each query's original index. Use path compression with union by size.
  1. Path Queries
    CF 1213G
    Hint
    Sort the edges; each union adds size[a] · size[b] pairs. Answer the sorted queries as you sweep.
    ~1800
  2. Minimize Malware Spread II
    LC 928
    Hint
    For each infected node, BFS while avoiding the other infected nodes. Count the clean nodes reached only from this one.
    ~2000
  3. Remove Max Number of Edges to Keep Graph Fully Traversable
    LC 1579
    Hint
    Add type-3 edges to both DSUs first, then type 1 and type 2.
    ~2150
  4. Checking Existence of Edge Length Limited Paths
    LC 1697★ core
    Hint
    Offline: sort the queries by limit and add edges with weight < limit.
    ~2300
  5. Number of Good Paths
    LC 2421★ core
    Hint
    Activate nodes in increasing value, uniting each with neighbours of value ≤ its own. For each value, a component with c such nodes adds C(c, 2) + c paths.
    ~2450
  6. Bricks Falling When Hit
    LC 803
    Hint
    Reverse time. Remove every hit, union the remaining bricks (with a virtual roof node), then add the hits back in reverse and measure how much the roof component grows.
    ~2750

MST tricks

How to spot it
Which edges must or can be in an MST, or adding vertex costs.
Key idea
Exclude an edge and see if the weight rises (critical). Force it in and see if the weight stays the same (pseudo-critical). Vertex costs become edges to the cheapest vertex.
Usual bug
An excluded edge can leave the graph disconnected; treat that weight as infinite.
  1. Make It Connected
    CF 1095F
    Hint
    Add edges from the minimum-a vertex to every vertex, then run Kruskal.
    ~1900
  2. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree
    LC 1489★ core
    Hint
    For each edge, run Kruskal without it (critical if the weight rises or the graph disconnects) and with it forced in (pseudo-critical if the weight equals the base).
    ~2550

Topological sort variants

How to spot it
Ordering with constraints, groups, separate row and column constraints.
Key idea
Separate dimensions get separate topological sorts. For groups, sort the groups, then the items inside each group.
Usual bug
Give each ungrouped item its own new group. Return empty on a cycle.
  1. Build a Matrix With Conditions
    LC 2392
    Hint
    Two independent topological sorts, one for rows and one for columns.
    ~1950
  2. Sort Items by Groups Respecting Dependencies
    LC 1203★ core
    Hint
    Two-level topological sort: groups first, then items within each group.
    ~2400

Euler paths (Hierholzer)

How to spot it
Use every edge exactly once, or the shortest string containing all codes.
Key idea
Hierholzer: append a node when you backtrack, then reverse. For a de Bruijn sequence, the nodes are (n-1)-length strings.
Usual bug
Start at the node with out - in = 1 if there is one. For lexicographic order, use a min-heap or sorted adjacency lists.
  1. Reconstruct Itinerary
    LC 332
    Hint
    Hierholzer with min-heap adjacency lists.
    ~2000
  2. Cracking the Safe
    LC 753★ core
    Hint
    De Bruijn sequence: an Euler circuit over the (n-1)-digit prefixes.
    ~2300
  3. Valid Arrangement of Pairs
    LC 2097
    Hint
    Find the start (out - in = 1), then Hierholzer.
    ~2650

Functional graphs (out-degree 1)

How to spot it
Each node points to exactly one next node: favourite person, next index, ball passing.
Key idea
Every component is one cycle with trees hanging into it. Peel the trees topologically. Use binary lifting for k steps.
Usual bug
2-cycles are a special case in some problems. Mark nodes with the timestamp of the current walk, not just 'visited'.
  1. Longest Cycle in a Graph
    LC 2360
    Hint
    Walk from each unvisited node, stamping times. Revisiting a node from the current walk gives the cycle length as the time difference.
    ~1900
  2. Count Visited Nodes in a Directed Graph
    LC 2876★ core
    Hint
    Nodes on a cycle get the cycle length. The rest get 1 + ans[next], computed in topological peel order.
    ~2200
  3. Maximum Employees to Be Invited to a Meeting
    LC 2127★ core
    Hint
    The answer is max(the largest cycle of length ≥ 3, the sum over all 2-cycles of 2 + the longest chains into both ends).
    ~2450
  4. Maximize Value of Function in a Ball Passing Game
    LC 2836
    Hint
    k goes up to 1e10. Binary lifting storing (node after 2^j steps, sum of ids along the way).
    ~2750

BFS on implicit state

How to spot it
Puzzles, keys and doors, boxes, buses: the graph isn't given directly.
Key idea
Define the state precisely, then BFS. Sometimes the right nodes are groups (bus routes), not individual stops.
Usual bug
Mark a state visited when you push it, not when you pop it. Keep the state as small as possible.
  1. Bus Routes
    LC 815★ core
    Hint
    BFS over routes rather than stops. Map each stop to its routes and mark each route used once.
    ~1950
  2. Shortest Path to Get All Keys
    LC 864★ core
    Hint
    BFS over (r, c, key mask).
    ~2250
  3. Minimum Moves to Move a Box to Their Target Location
    LC 1263
    Hint
    BFS over (box position, player side). For each push, run an inner BFS to check the player can reach the pushing cell.
    ~2300

Bipartite & layering

How to spot it
Split into groups where edges join adjacent groups, or 2-colouring.
Key idea
Each component must be bipartite. The maximum number of layers is the largest BFS eccentricity, tried from every node.
Usual bug
Add up the answers over components separately.
  1. Divide Nodes Into the Maximum Number of Groups
    LC 2493★ core
    Hint
    If any component isn't bipartite, return -1. Otherwise sum, over components, the maximum BFS depth from any start node in it.
    ~2400

Minimax paths

How to spot it
Minimise the maximum height, effort or time along a path.
Key idea
Dijkstra where the path cost is max instead of sum, or binary search + BFS, or DSU over sorted cells.
Usual bug
Include the start cell's own value.
  1. Swim in Rising Water
    LC 778★ core
    Hint
    Union cells in order of height until the start and end are connected; equivalently, Dijkstra with max.
    ~2100