Geometry for OAs

research-backed · offline · no account

Remove geometry as a source of uncertainty.

Not “learn computational geometry.” The goal is narrower and more useful: if a strong company puts an unfamiliar geometry-flavoured problem in front of you, you recognise the structure, pick the primitive, implement it correctly, and handle the degeneracies — under a clock. Everything in this file was selected against that target and nothing else.

What the research changed about the plan

I pulled the numbers before designing any of this, and two findings reshaped it:

  1. Pure 2-D geometry is rare — about 1% of company-tagged problems — and it collapses onto roughly six primitives. There is no long tail worth learning.
  2. The highest-frequency “geometry” carries no geometry tag at all. It is the 1-D projection: intervals and sweep. Merge Intervals is tagged by 21 of 25 companies; the best-represented problem in the actual geometry tag is tagged by 10.

So this is not a computational geometry course with the hard parts removed. It is a different shape from one. The Research tab shows the working.

The plan, and where the stop line is

BlockContentHoursStatus
WEEK 1 Corenumeric ritual · cross product · distance & metrics · rectangles · point-set hashing · interval sweep12–14Non-negotiable. Covers ~85% of observed geometry.
WEEK 2 Closingsegments & degeneracies · polygons · angular window · convex hull · Chebyshev rotation · circles7–9Deferrable behind graphs and DP. Run it in gaps.
Maintenancetwo problems a week, written from memory, no reference0.5/wkRetention is where this evaporates, so this line is not optional.
If you only get one week

Stop after §7 (interval sweep). Do not start §8–11. A complete, reliable Tier A beats a shaky Tier A+B every time — a primitive you half-remember under a clock is worse than one you know you don’t have, because the half-memory costs you fifteen minutes before you abandon it.

Six sessions

SessionReadThen typeProblems
1 · ~2hNumeric ritual, §1 distance, §2 cross productP, cross, orient, dist2 — from scratch, no copyingg1, g4, g5, g6
2 · ~2h§3 trianglespointInTriangle, then run selftest.cppg7, g10, plus re-solve your Oracle problem end to end
3 · ~2h§5 rectanglesoverlapArea, overlapAreaValueg12, g13, g14
4 · ~2.5h§6 point-set hashingslopeKey — this is the one to get exactly rightg8, g9, g11
5 · ~2h§7 interval sweepmaxOverlap, and the merge loopg17, g18, g20
6 · ~2hnothing — close the filethe whole toolkit from memory, then diff against toolkit/geo.hppTimed Set 1, scored

How to use the file

The readiness standard

You are ready when you can do all of these, not most:

What this does not claim

No curriculum makes an offer more likely by itself, and I am not going to tell you this one does. What it can honestly do is convert one specific variable from luck into preparation. If you fail the standard above, the Reference tab has the repair table: which failure points at which section.

Part I — what geometry actually appears

Everything below was pulled from primary sources on 16 September 2026 and every problem reference was resolved against its source before it was written down. Where the evidence is thin I say so rather than rounding it up.

Method, and its limits

  • LeetCode GraphQL problem API. 4,055 public problems; 46 carry the geometry tag — 1.13% of the corpus.
  • 25 company tag sets from a public mirror of LeetCode Premium's company tags, snapshot 20 June 2025: Oracle, Google, Microsoft, Amazon, Meta, Apple, Uber, Bloomberg, Adobe, Atlassian, Salesforce, Walmart Labs, Directi, Media.net, Trilogy, Visa, Goldman Sachs, DE Shaw, TikTok, Nvidia, LinkedIn, Flipkart, Citadel, Zoho, Samsung. I cross-referenced these against the 46 by slug and by frequency score.
  • Codeforces problemset API. 430 geometry-tagged problems with ratings and solve counts; 160 in the 800–1900 band that is plausibly OA-shaped.
  • Kattis for the primitive-drill problems, each slug verified by HTTP.
What this evidence is and is not

Tier 1 — repeatedly reported. The company tag frequencies. They are crowd-sourced from candidates who saw a problem in a real process, aggregated over many reports. Directionally reliable, and the only quantitative signal available at this scale.

Tier 3 — reasonable proxy. Codeforces and Kattis ratings and tags. These say nothing about OAs; they say a problem trains a technique.

Known limits, stated plainly. LeetCode tags skew towards companies that use LeetCode-style screens, which under-represents CodeSignal and HackerRank shops. Frequency scores are relative within a company, not across companies. A small tag set — Directi has 8 problems, Trilogy 6 — supports no conclusion at all, and I have not drawn one. And a company tag set is a sample of what candidates chose to report, not a question bank.

Finding 1 — the frequency, company by company

CompanyProblems taggedGeometry%Its top geometry problems
Google2344311.323625 trapezoids (49) · 939 min-area-rect (42) · 963 rotated rect (35)
Amazon2011160.80973 k-closest (47) · 149 max-points (24) · 2101 bombs (18)
Meta1399141.00973 k-closest (77) · 1266 min-time (30) · 149 max-points (28)
Microsoft1384130.943009 intersections (27) · 836 rect-overlap (25) · 223 rect-area (22)
Bloomberg1223110.90812 largest-triangle (25) · 149 (21) · 973 (21)
Uber35920.563027 place-people-II (52) · 2101 bombs (34)
Oracle29910.33973 k-closest (25)
Apple29820.67149 (51) · 973 (30)
Salesforce19310.52973 k-closest (36)
Nvidia13632.211610 visible-points (68) · 223 (52) · 149 (37)
Media.net3512.861266 min-time (86) — tiny sample, do not over-read
Adobe · Atlassian · Visa · Walmart · DE Shaw · Directi · Trilogy · Samsung—00.00no geometry-tagged problem in any of their sets

Read that last row carefully. Eight of twenty-five companies — including three on your target list — have no geometry in their tag set at all. Geometry is concentrated in Google, Meta, Amazon, Microsoft, Bloomberg and Nvidia. If your pipeline is weighted towards the Indian product companies and services-adjacent shops, the honest expected value of this whole subject is lower than the effort people put into it. Week 1 is the right investment. Three weeks would not be.

Finding 2 — the 1-D projection dominates, and it is not tagged geometry

ProblemCompanies tagging itPeak frequencyWhat it really is
LC 56 · Merge Intervals21/2593 (Zoho)1-D segments, sorted
LC 253 · Meeting Rooms II17/2584 (TikTok)event sweep
LC 1353 · Max Events That Can Be Attended12/2573 (Visa)sweep + heap
LC 729 · My Calendar I9/2573 (Uber)interval overlap, online
LC 218 · The Skyline Problem8/2539 (Goldman Sachs)2-D → sweep with a heap
LC 986 · Interval List Intersections7/2574 (Meta)two-pointer on intervals
LC 452 · Min Arrows to Burst Balloons7/2549 (Zoho)greedy stabbing
— for comparison —
LC 973 · K Closest Points (best geometry-tagged)10/2577 (Meta)sorting with a metric
The conclusion that changed this curriculum

The 1-D projection is two to three times more widely tagged than the best-represented problem in the geometry tag, and ten to twenty times more than the median one. Yet it is filed under sorting, greedy and heap — so people preparing ‘geometry’ skip it, and people preparing sorting never connect it to rectangles and skylines.

That gap is where the actual OA risk lives, and it is why §7 is Tier A rather than an appendix.

Finding 3 — the shape of the geometry that does appear

Of the 46 geometry-tagged problems, sorted by how many companies tag them, the top of the list is: 973 (10), 149 (10), 1266 (6), 223 (6), 939 (4), 2101 (4), 836 (4), 3025 (4), 3047 (4), 2481 (4). Below that, the distribution collapses — 22 of the 46 are tagged by exactly one company, and 8 by none at all.

Grouping those by what they actually require:

ClusterShare of the tagged setVerdict
Metric + ordinary algorithm — distance as a sort key, a filter, or a graph edge~35%Tier A. The geometry is one line; the problem is sorting, hashing, heap or BFS.
Axis-aligned rectangles — overlap, area, finding them in point sets~25%Tier A. Reduces to interval logic on two axes.
Cross-product reasoning — collinearity, area, orientation, convexity~20%Tier A. One primitive, many disguises.
Sweep in two dimensions — skyline, rectangle union, chart intersections~10%Tier B. Worth the time; the ideas transfer.
Genuine advanced CG — hull, minimum enclosing circle, ternary search on a surface~10%Tier C/D. Convex hull earns one evening; the rest earns a name.

Finding 4 — recency

Restricting to each company's most recent six-month slice in the snapshot, geometry nearly vanishes, and what remains is concentrated: Amazon 2 (149, 973), Bloomberg 2 (973, 149), Google 3 (3464, 223, 963), Meta 1 (973), Microsoft 1 (223). Sixteen of the twenty-five companies show zero geometry in their recent slice.

How to read that without over-reading it

The recent slices are small, so absence is weak evidence. But the concentration is informative and consistent with the whole-period data: when geometry does show up recently, it is 973, 149 and 223 — k-closest, max-points-on-a-line, and rectangle area. Those three problems are Session 1, Session 3 and Session 4 of the plan, which is how the sessions were ordered.

Coverage matrix

Priorities below come from the evidence above, not from what a geometry textbook would emphasise.

SkillEvidenceTierLearnGuidedMixedTimed
Squared distance & metricsLC 973 in 10/25 cos, freq 77; LC 1266 in 6/25A✓✓✓✓
Cross product / orientationLC 149 in 10/25; 1037, 1232, 812, 469, 3623 all reduce to itA✓✓✓✓
Triangle degeneracy & containmentyour Oracle OA; LC 812, 3588; CF 6A, 1398AA✓✓✓✓
Axis-aligned rectanglesLC 223 in 6/25, 836 in 4/25, 939 in 4/25, 3047 in 4/25A✓✓✓✓
Point-set hashingLC 149, 447, 593, 939, 963, 2013, 3623, 3625A✓✓✓✓
Interval / 1-D sweepLC 56 in 21/25, 253 in 17/25, 1353 in 12/25, 729 in 9/25A✓✓✓✓
Segment intersectionLC 335 (Bloomberg) only; strong proxy value on KattisB✓✓✓—
Polygon area & containmentLC 812, 469, 587; Kattis; CF 1942CB✓✓✓—
Angular window (atan2)LC 1610 — Nvidia freq 68, Google, Amazon; CF 257CB✓✓✓✓
Sweep in 2-D (rect union, skyline)LC 218 in 8/25, 850 (Flipkart 60), 391 in 3/25, 3009 (Microsoft 27)B✓✓✓✓
Convex hullLC 587 (Google, Amazon) and LC 1924 (Google) — that is allC✓✓—✓
CirclesLC 1401, 1828, 2249, 2101 — all reduce to dist2 vs r²C✓✓✓—
Chebyshev / L1 rotationLC 3102, 1266, 296, 462; CF 650AC✓✓——
Minimum enclosing circleLC 1924 (Google, premium), 1453 (Meta) — two problems totalDname only———
Rotating caliperszero occurrences in 25 company tag setsDname only———
Half-plane intersection, Voronoi, Delaunay, k-d trees, 3-D hull, Bentley–OttmannzeroD————

What is deliberately excluded, and why

ExcludedEvidenceIf an interviewer raises it
Rotating calipers0 occurrences in 25 company sets; the farthest-pair problems that exist have n small enough for O(n²)“Hull first, then walk antipodal pairs in linear time — but at these constraints I'd brute-force the hull points.”
Half-plane intersection0 occurrencesName it, say it is O(n log n) by dual sorting, move on.
Voronoi / Delaunay0 occurrencesName it. Nearest-neighbour structure. Never hand-implemented in an interview.
k-d treesappears only as a LeetCode topic label on LC 973, where a heap is the intended answerMention it as the n-large structure; give the heap or quickselect answer.
Bentley–Ottmann sweep0 occurrencesName it as the O((n+k) log n) all-intersections algorithm.
3-D geometryonly LC 883/892, which are matrix-summation problems in a 3-D costume—
Circle–circle intersection area, tangent lines, circumcircles0 occurrences in company setsEvery circle problem in the data is dist2 vs r².
Convex hull trick (DP optimisation)despite the name, a DP technique, not geometryIt belongs in your DP preparation.

Before any of it: pick your number type

Geometry solutions die in the arithmetic more often than in the idea. Two minutes of this at the top of a problem buys you the rest of it.

The thirty-second ritual

Read the constraint line and find the largest absolute coordinate. Call it C.

  1. A difference b.x - a.x is at most 2C.
  2. A cross product is a difference times a difference, minus another such product — roughly 2 × (2C)² = 8C².
  3. A squared distance is (2C)² + (2C)² = 8C².
  4. Compare 8C² against 9.22 × 1018, the ceiling of a signed 64-bit integer.
C (max coordinate)8C²int (2.1e9)long long (9.2e18)verdict
1048 × 108✅ fits✅int survives; use long long anyway
1058 × 1010❌ overflows✅long long required
1098 × 1018❌✅ barely — 87% of the rangelong long, no headroom left
109, then summed> 9.2 × 1018❌❌__int128, or restructure

Watch the last row. One cross product at C = 109 fits. A shoelace sum of a thousand of them does not. When you accumulate, the ceiling applies to the accumulator rather than to each term.

The overflow that looks correct

It compiles without a warning, and it is the most common geometry bug in an OA:

int cross(Point a, Point b, Point c) {
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);   // int arithmetic
}

Here it is again wearing a correct return type:

long long cross(Point a, Point b, Point c) {
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);   // STILL int arithmetic
}

If x and y are int, every subtraction and every multiplication happens in int. By the time the result widens to long long, the damage is done.

Declare the members long long. Do not cast at the call site. Casts you have to remember get dropped once you are behind the clock.

struct P {
    long long x, y;                       // long long HERE — this is the fix
};

long long cross(P a, P b, P c) {          // (b-a) x (c-a)
    return (b.x - a.x) * (c.y - a.y)
         - (b.y - a.y) * (c.x - a.x);
}

Six rules that cover every OA you will see

SituationWhat to doWhy
Comparing two distancescompare dist2, never distsqrt is monotone on non-negatives, so the order is identical and you stay exact
Testing a point against a circledx*dx + dy*dy vs r*rsame trick, and it dodges the double equality question at the boundary
Deciding left / right / collinearsign of an integer cross productthe answer is a sign, so it needs no division and no float
Polygon or triangle areakeep 2×area as an integer; halve only when printingtwice the area of an integer polygon is always an integer
A slopethe reduced pair (dx/g, dy/g) with a fixed signdouble merges slopes that differ and splits slopes that don't
A midpointstore (x1+x2, y1+y2) — the suman average needs a /2, which truncates silently on odd sums
When floating point is genuinely unavoidable

Three situations, and no others in this scope: an angle (atan2), a real-valued answer you have to print, and a ternary search over a continuous parameter. There:

  • Use long double. It costs nothing and buys three or four decimal digits.
  • Size EPS against the magnitudes in play. At coordinates near 109, an absolute 1e-9 is finer than the gap between representable doubles up there, so it does nothing whatsoever.
  • Never compare two floats with ==, and never sort on a float key when an exact integer key exists.

TIER A1 · Distance, and the sqrt you must not write

Distance is the most widely tagged geometry there is, and the technique is one line. The work lies in seeing what is left once you peel the metric off.

Why this comes first

LC 973 · K Closest Points to Origin is tagged by 10 of the 25 companies I pulled — Meta at frequency 77, then Salesforce, Apple, Google, LinkedIn, Oracle, Bloomberg, Goldman Sachs, Microsoft and Amazon. Nothing else in the geometry tag is tagged that widely.

Across the dataset a metric usually sits on top of an ordinary algorithm, serving as a sort key, a filter, or a graph edge. Getting quick at peeling it away is worth more than any individual formula.

The idea

You need to know which of two points is closer, and your hand goes to sqrt. Stop. sqrt is monotonically increasing on non-negative numbers:

d(A) < d(B) ⇔ d(A)² < d(B)²

So any question about the order of distances can be settled on squared distances. For integer points those are integers, making the comparison exact and epsilon-free. You need a real square root only when a length has to be printed.

long long dist2(P a, P b) {
    long long dx = a.x - b.x, dy = a.y - b.y;
    return dx*dx + dy*dy;
}

Three metrics

MetricFormulaUnit ballWhat signals it in a statement
Euclidean√(dx² + dy²)circlephysical distance; the word radius
Manhattan (L1)|dx| + |dy|diamond4-directional grid movement; city blocks
Chebyshev (L∞)max(|dx|, |dy|)square8-directional movement, a king's move, “diagonal steps allowed”

Separability

Manhattan distance splits into an x-part and a y-part that never interact. An L1 problem in the plane is therefore often two independent one-dimensional problems: solve each axis alone, combine at the end.

Euclidean distance offers no such split. A square root couples the axes, and coordinate-wise reasoning stops being valid the moment one shows up inside a minimisation. This is why the L1 version of a minimisation is frequently easy while the L2 version of the same sentence needs numerical methods, and why the L2 ones make poor OA questions.

Chebyshev separates too, after a change of coordinates:

Manhattan ball|dx| + |dy| ≤ r(x+y, x−y)Chebyshev ballmax(|du|, |dv|) ≤ rOne rotation turnsa coupled 2-D maxinto two independent1-D ranges.
Map every point through (u, v) = (x + y, x − y). Chebyshev distance in the original plane becomes half the Manhattan distance in the new one, and the reverse holds as well. A 45°-rotated square turns into an axis-aligned one.
// Chebyshev  ->  Manhattan
long long u = x + y, v = x - y;
// a coupled max(|dx|,|dy|) becomes two ranges you can handle independently

You will not reach for the rotation often. When you do, nothing else substitutes, and it costs four characters. The tell is a max binding |dx| to |dy|, or a region described by |x| + |y| ≤ r.

SpoilerThis gives away LC 296 · LC 296 Best Meeting Point, LC 462 · LC 462 Min Moves to Equal Array Elements II and CF 650A · CF 650A Watchmen. Skip it until you have attempted them — the concept above stands on its own without it.

Two worked payoffs of the properties above. Each is the crux of the problems named, which makes them the part worth deriving rather than reading.

  • Minimising total L1 distance to a set of points. Separability lets you minimise over x and over y independently, and in one dimension the minimiser of a sum of absolute deviations is the median. The answer is (median of the xs, median of the ys), so the planar problem is the 1-D problem run twice.
  • When does Manhattan equal Euclidean? Precisely when dx or dy is zero, meaning the two points share a row or a column. A distance question becomes two hash-map counts and the geometry disappears.
Two ways this section gets you
  1. sqrt followed by ==. Any shape-classification question that compares lengths for equality is exact on dist2 and approximate on double. The double version clears the samples and fails on large coordinates.
  2. dist2 can overflow where dist would not. Squaring is what carries you over the 64-bit ceiling. Run the ritual.

TIER A2 · The cross product

Learn this one properly. Nine of the eleven Tier A/B techniques below are built out of it.

Start from the question

Here is the situation that actually arises. You have a directed line from A to B and a third point C, and you need to know whether C lies to the left of that line, to the right of it, or exactly on it.

Triangle validity, point containment, segment crossing, polygon orientation, convexity and convex hull are all that question asked repeatedly.

ABCcross > 0LEFT / counter-clockwiseABCcross = 0COLLINEARABCcross < 0RIGHT / clockwise
One integer, three outcomes. The sign of cross(A,B,C) answers ‘which side’ with no division, no square root and no epsilon.

Deriving it, so you never have to memorise it

Write the two vectors leaving A: u = B − A and v = C − A. The 2-D cross product of two vectors is the scalar

u × v = u.x · v.y − u.y · v.x

Two properties make it useful, and both are worth holding rather than trusting:

  1. Its magnitude is the area of the parallelogram spanned by u and v, so half of it is the area of triangle ABC.
  2. Its sign is positive when v is counter-clockwise from u, negative when clockwise, and zero when the two are parallel — which, for these particular vectors, means A, B and C are collinear.
ABCu = B−Av = C−A|u × v|= area of the parallelogram|u × v| / 2= area of triangle ABCSign says which side C is on.Zero area ⇔ no triangle at all.
Magnitude and sign fall out of the same number, which is how one integer answers both ‘how big is this triangle’ and ‘which way does it turn’.

Substituting u = B − A and v = C − A gives the form you write:

long long cross(P a, P b, P c) {          // sign: + left, - right, 0 collinear
    return (b.x - a.x) * (c.y - a.y)
         - (b.y - a.y) * (c.x - a.x);
}

int orient(P a, P b, P c) {               // squashed to -1 / 0 / +1
    long long v = cross(a, b, c);
    return (v > 0) - (v < 0);
}
Why the sign form beats the slope form

You could answer ‘which side’ by comparing slopes: is (c.y-a.y)/(c.x-a.x) greater than (b.y-a.y)/(b.x-a.x)? Multiply through by the two denominators and the cross product drops out. They are the same inequality.

The slope version carries two divisions, so it needs a zero-denominator case for vertical lines, floating point, and an epsilon. The cross product has already cleared the denominators. Once you have seen that, it stops being a formula you have to trust.

What this one function answers

QuestionExpressed with cross
Are A, B, C collinear?cross(a,b,c) == 0
Do A, B, C form a real triangle?cross(a,b,c) != 0
Area of triangle ABCabs(cross(a,b,c))  (that is 2×area)
Is the turn at B a left turn?cross(a,b,c) > 0
Is this polygon convex?all consecutive crosses share one sign
Was the polygon given clockwise?sign of the shoelace sum
Do segments AB and CD cross?four orientation tests (§4)
Is P inside triangle ABC?three crosses, signs compared (§3)
Three ways people get this wrong
  1. Argument order. cross(a,b,c) and cross(b,a,c) carry opposite signs. Fix one convention — first two arguments are the directed line, third is the query point — and hold it everywhere, including inside loops where reordering looks harmless.
  2. int operands. Covered above. Worth repeating because it costs whole problems rather than single test cases.
  3. Writing > 0 when the shape might be clockwise. A test that assumes counter-clockwise input inverts silently on clockwise input. Either normalise the winding first or compare the three signs against each other rather than against zero.

TIER A3 · Triangles

Non-degeneracy, area, containment — and the reason your Oracle problem’s own framing worked against you.

The problem you lost

Three points A, B, C and two query points P, Q. Decide whether ABC is a non-degenerate triangle, then whether P and Q lie inside it. The statement framed validity through side-length inequalities: a + b > c, and the other two.

That framing is correct mathematics and a bad computational plan. Follow it literally and you take three square roots, compare three floating-point sums, and inherit an epsilon problem — all for a question whose answer is one integer compared against zero.

You knew the cross product. What you needed was to hear “valid triangle” and think “not collinear”. That translation is the trainable part, and the Recognition tab drills it.

Non-degeneracy

valid triangle ⇔ positive area ⇔ not collinear ⇔ cross(A,B,C) ≠ 0
bool isTriangle(P a, P b, P c) {
    return cross(a, b, c) != 0;          // exact: no sqrt, no epsilon, no side lengths
}

One test covers the cases the side-length form makes you enumerate by hand. Two coincident points, three identical points, and three points on a line all give cross == 0, and all get rejected.

When side lengths are the right tool

If the input is a list of lengths rather than points — sticks, rods, edges with no coordinates — then a cross product has nothing to act on and the triangle inequality is all you have. Sorting usually follows.

Points give you the cross product. Lengths give you the inequality. Reading which one you were handed is half the recognition skill, and statements move between them freely.

Area

long long twiceArea(P a, P b, P c) {
    return llabs(cross(a, b, c));        // keep it doubled — stays an integer
}

Halve at the very end, and only to print. If the problem compares or maximises areas, don't halve at all — the comparisons agree either way, and you stay in exact integers.

Containment

ABCPQP: all three the same sign→ strictly insideQ: signs disagree→ outsideany cross = 0→ on that edge’s line;   on the edge if the   others agree
Walk the edges as directed segments A→B, B→C, C→A. A point strictly inside lies on the same side of all three. Disagreeing signs put it outside. A zero means the point sits on that edge’s line.

The version below reasons about the three signs instead of assuming a counter-clockwise triangle, which is what lets it survive arbitrary input:

// returns  1 = strictly inside,  0 = on the boundary,  -1 = outside
// precondition: a, b, c is a non-degenerate triangle (check first!)
int pointInTriangle(P a, P b, P c, P p) {
    int d1 = orient(a, b, p);
    int d2 = orient(b, c, p);
    int d3 = orient(c, a, p);

    bool hasNeg = (d1 < 0) || (d2 < 0) || (d3 < 0);
    bool hasPos = (d1 > 0) || (d2 > 0) || (d3 > 0);
    if (hasNeg && hasPos) return -1;               // signs disagree -> outside

    if (d1 == 0 || d2 == 0 || d3 == 0) return 0;   // touching an edge or vertex
    return 1;                                      // all strictly same sign
}
Settle the boundary before you type

“Inside” is ambiguous and statements resolve it differently. Find the sentence that says whether a point on an edge counts, and whether a vertex counts. Decide what this function returns for each, and put it in a comment before you write the body.

Returning tri-state 1/0/-1 rather than a bool keeps that decision a one-line change later instead of a rewrite.

The ‘sum of three areas’ test is weaker

A popular alternative says P is inside iff area(ABP) + area(BCP) + area(CAP) == area(ABC). True, and it costs more:

  • Three absolute values and an equality test against three signs — more arithmetic, and more of your overflow headroom spent.
  • Written in double it fails at the boundary, which is where the hidden tests live.
  • It cannot separate ‘on an edge’ from ‘strictly inside’ without extra work, and that distinction is usually what the question turns on.

Your recovery for that OA

// 1. degenerate?
if (cross(A, B, C) == 0) { cout << "not a triangle"; return; }
// 2. each query point
for (P q : {P_, Q_}) {
    int r = pointInTriangle(A, B, C, q);
    cout << (r == 1 ? "inside" : r == 0 ? "on boundary" : "outside") << '\n';
}

TIER A5 · Axis-aligned rectangles

By the company data, the largest block of genuine 2-D geometry that gets asked — and the block with the least geometry inside it.

The one idea

An axis-aligned rectangle is a pair of intervals, one on x and one on y. Two rectangles overlap exactly when their x-intervals overlap and their y-intervals overlap. No 2-D reasoning is involved at any point.

R1R2x-intervals overlapy-intervals overlapoverlap⇔ x-intervals overlap   AND y-intervals overlapTwo dimensions, zerogeometry. It is 1-Dinterval logic, twice.
Project onto each axis. Two independent 1-D questions joined by an AND. Seen this way, a rectangle problem becomes interval arithmetic, which you already own.
struct R { long long x1, y1, x2, y2; };   // x1<x2, y1<y2

// do they share positive AREA?  (touching edges do NOT count)
bool overlapArea(R a, R b) {
    return max(a.x1, b.x1) < min(a.x2, b.x2)
        && max(a.y1, b.y1) < min(a.y2, b.y2);
}

// do they touch or overlap?  (shared edge or corner DOES count)
bool overlapClosed(R a, R b) {
    return max(a.x1, b.x1) <= min(a.x2, b.x2)
        && max(a.y1, b.y1) <= min(a.y2, b.y2);
}

// area of the overlap (0 if none)
long long overlapAreaValue(R a, R b) {
    long long w = min(a.x2, b.x2) - max(a.x1, b.x1);
    long long h = min(a.y2, b.y2) - max(a.y1, b.y1);
    return (w > 0 && h > 0) ? w * h : 0;
}
< versus ≤

Those two functions differ by two characters and disagree on exactly the test case a grader cares about. Some statements say rectangles sharing only an edge do not overlap; others say they do. Find that sentence, then write the comparator to match it.

Samples rarely contain a tangency, so the mistake stays invisible until the hidden tests.

Notice that overlapAreaValue clamps each axis separately. Multiplying two negative extents together produces a positive phantom overlap, which is the other way this gets you. Inclusion–exclusion then gives the union of two rectangles:

long long areaUnion(R a, R b) {
    long long A = (a.x2-a.x1)*(a.y2-a.y1);
    long long B = (b.x2-b.x1)*(b.y2-b.y1);
    return A + B - overlapAreaValue(a, b);
}

At three or more rectangles inclusion–exclusion needs 2n terms and you switch to a sweep, covered in §7. Recognising where that switch happens is most of the skill.

Rectangles hidden in a point set

A second and very common family hands you points and asks about rectangles they form. The geometry is trivial; the work is choosing a hash key and deciding which pairs to iterate over.

Three reusable ideas, stated without reference to any particular problem:

SpoilerThis gives away LC 939 · LC 939, LC 963 · LC 963, LC 2013 · LC 2013 and LC 391 · LC 391 Perfect Rectangle. Skip it until you have attempted them — the concept above stands on its own without it.

The four concrete instantiations, for checking your reasoning after you have attempted them.

Shape of questionThe move
smallest axis-aligned rectangle from a point sethash the points; for each pair with differing x and differing y, treat it as a diagonal and look up (x1,y2) and (x2,y1)
smallest rectangle at any angletwo segments are the diagonals of a rectangle iff they share a midpoint and a length; group point pairs by (x1+x2, y1+y2, dist2)
counting squares against streamed pointscount by diagonal — for each query point, walk stored points with |dx| == |dy| ≠ 0 and multiply the counts of the two missing corners
do these rectangles tile a perfect rectangle exactlythe two sufficient invariants are total area equal to the bounding box, and corner parity: toggle all four corners of every rectangle in a set, and exactly the four outer corners must survive. Area alone permits a gap cancelling an overlap; parity alone permits other degenerate layouts

TIER A6 · Point-set hashing

Geometry that is really a hash map. What these problems test is exact integer normalisation.

Canonical slope

LC 149 · Max Points on a Line is tagged by 10 of 25 companies — LinkedIn at 56, then Apple, Citadel, Zoho, Nvidia, Meta, Google, Amazon, Bloomberg and Microsoft. Its acceptance rate is 31%, which is low for a problem whose algorithm is short and fairly obvious. The difficulty sits entirely in how you represent a slope.

A double slope is a wrong answer, not a slow one

double s = (double)dy / dx; loses to three separate things: division by zero on vertical lines, two genuinely different slopes rounding to the same double, and one slope computed from two different pairs rounding to two different doubles. All three turn up in real test sets.

raw (dx, dy)normalisehash key(4, 6)gcd 2(2, 3)(-2, -3)flip sign(2, 3)(0, -5)vertical(0, 1)(7, 0)horizontal(1, 0)
Reduce by the gcd, then force one representative per direction by fixing the sign. Equal slopes become equal keys, exactly, with no floating point anywhere.
// canonical direction of the line through a and b
pair<long long,long long> slopeKey(P a, P b) {
    long long dx = b.x - a.x, dy = b.y - a.y;
    long long g = std::gcd(llabs(dx), llabs(dy));
    if (g) { dx /= g; dy /= g; }
    // force one representative per direction
    if (dx < 0 || (dx == 0 && dy < 0)) { dx = -dx; dy = -dy; }
    return {dx, dy};
}

Read the sign-fixing line closely, because correctness lives there. After gcd reduction (2,3) and (-2,-3) describe the same line but hash differently. “If dx is negative, flip both” repairs that — except when dx == 0, where flipping on dx's sign does nothing and (0,5) and (0,-5) stay apart. Hence the second clause. Vertical lines are what people forget.

gcd(0, 0)

std::gcd(0,0) is 0, and dividing by it is undefined behaviour. The if (g) guard covers coincident points. When duplicates are possible in the input, count them separately and add them to every line's total. Whether they are possible is a constraint-line question, and the answer varies.

One level up: canonical line

A slope identifies a direction. To count distinct lines, or to detect parallel ones, use the implicit form Ax + By + C = 0 with A = dy, B = -dx and C = -(A·x₁ + B·y₁), then reduce the whole triple by gcd(|A|,|B|,|C|) and fix the sign the same way. CF 1163C1 · Power Transmission (Easy Edition) and its hard version drill this directly.

The three canonical keys

Nearly every point-set counting problem in the dataset is one of these dropped into a map, followed by a k·(k−1)/2.

  • Direction: (dx, dy) reduced by gcd, sign fixed.
  • Length: dist2, never dist.
  • Midpoint: (x₁+x₂, y₁+y₂), the sum, so it stays integral.

Combining two of them identifies a shape. Segments sharing a midpoint are the diagonals of a parallelogram; sharing a midpoint and a length makes it a rectangle; add perpendicularity and it is a square. Derive the rest from there.

Grouping by exact distance

A family of shape-classification and counting questions reduces to this: compute all pairwise dist2 from an anchor, group them, count within groups. Everything stays integral, so equality is real equality rather than an approximation.

Decide whether the problem counts ordered or unordered pairs before you write k*(k-1) or k*(k-1)/2. That factor of two is a frequent wrong answer.


TIER A7 · The 1-D projection — intervals and sweep

The highest-frequency ‘geometry’ in the dataset, carrying no geometry tag. Most likely to be tested, least likely to be filed under geometry.

What the data said

Across the 25 company tag sets: LC 56 · Merge Intervals appears in 21. LC 253 · Meeting Rooms II in 17. LC 1353 · Maximum Number of Events That Can Be Attended in 12. LC 729 · My Calendar I in 9. LC 218 · The Skyline Problem in 8.

Inside the geometry tag proper, the best-represented problem appears in 10 sets and the median appears in 1. If your hours are limited, spend them here.

Why it belongs in a geometry file

Because it is geometry, collapsed. A meeting is a segment on a time line. A building in a skyline is a rectangle. A rectangle in a union-of-areas problem is an interval that stays alive over a range of y. Once you notice that a 2-D problem only ever asks about one axis at a time, it reduces to this.

sweep++−+−+−−−3 alive
Turn each interval into two events: +1 at its start, −1 at its end. Sort them, walk left to right, keep a running counter. The counter is how many intervals are alive at that x.
// max number of simultaneously-alive intervals
int maxOverlap(vector<pair<long long,long long>> iv) {
    vector<pair<long long,int>> ev;
    for (auto [s, e] : iv) { ev.push_back({s, +1}); ev.push_back({e, -1}); }
    sort(ev.begin(), ev.end());          // ties: -1 sorts before +1, so touching does NOT overlap
    int cur = 0, best = 0;
    for (auto [x, d] : ev) { cur += d; best = max(best, cur); }
    return best;
}
Tie-breaking at equal coordinates is the real difficulty

When one interval ends exactly where another begins, do they overlap? The code above says no: pair sorting puts {{x,-1}} before {{x,+1}}, so the close is processed first. Encode the events as {{x,0}} for open and {{x,1}} for close and you get the opposite convention.

Both are correct for some problem and neither is correct for all of them. A meeting ending at 10:00 does not conflict with one starting at 10:00, but two segments touching at a point usually do count as touching. Read the statement, choose, and write the reason in a comment so you do not flip it back later when a sample appears to disagree.

The four moves

MoveCostUse when
Sort by start, merge as you goO(n log n)you need the merged intervals themselves
Event sweep with a counterO(n log n)you need a count, a maximum, or an integral
Sweep with a heapO(n log n)you need to know which interval is on top right now
Difference array / prefix sumsO(n + range)coordinates are small and dense

Lifting it back to 2-D

For the area of a union of many rectangles, sweep a vertical line across x. At any x the shape is a set of y-intervals, and the area between consecutive x-events is (total covered y-length) × (Δx). The new ingredient is coordinate compression: only y values appearing as rectangle edges can change the covered length, so there are at most 2n of them.

Where to stop

The textbook version maintains covered length in O(log n) using a segment tree with a lazy count of covering intervals. You do not need that here. At OA sizes, recomputing covered length by scanning the compressed y-array is O(n) per event and O(n²) overall, which passes and which you can write correctly under pressure.

Being able to name the segment-tree version is worth a sentence in an interview. Implementing it is three hours you need for graphs.


TIER B4 · Segments

Tier B: dedicated segment-intersection questions are uncommon in the company data. The degenerate cases are still the best edge-case training in the subject, and ‘do the paths cross’ is exactly the wording that produces a blank page.

Point on segment

Two conditions, both required. Collinearity puts the point somewhere on the infinite line; the bounding box clips it back to the segment.

bool onSegment(P a, P b, P p) {        // is p on segment ab (endpoints included)?
    if (cross(a, b, p) != 0) return false;                    // not even on the line
    return min(a.x, b.x) <= p.x && p.x <= max(a.x, b.x)       // inside the box
        && min(a.y, b.y) <= p.y && p.y <= max(a.y, b.y);
}

Order matters here. A box test on its own admits points off the line, but a box test applied after the collinearity test cannot produce a false positive: a point both on the line and inside the box is necessarily on the segment. A zero-length segment (a == b) also works with no special case — the cross is zero for every p, and the box collapses to a single point.

Do two segments intersect?

propertouch at endpointcollinear, overlapcollinear, disjointparallellines cross, segments don't
Six configurations. Everything in the top row counts as intersecting; nothing in the bottom row does. A naive implementation gets the top-left panel right and loses at least two of the rest.

The general case first. Segments AB and CD cross properly when C and D lie on opposite sides of line AB, and A and B lie on opposite sides of line CD. Both halves are needed — the bottom-right panel is exactly where one holds and the other does not.

bool segIntersect(P a, P b, P c, P d) {
    int d1 = orient(a, b, c), d2 = orient(a, b, d);
    int d3 = orient(c, d, a), d4 = orient(c, d, b);

    // proper crossing: strictly opposite sides, both ways
    if (d1 * d2 < 0 && d3 * d4 < 0) return true;

    // degenerate: an endpoint lies on the other segment
    if (d1 == 0 && onSegment(a, b, c)) return true;
    if (d2 == 0 && onSegment(a, b, d)) return true;
    if (d3 == 0 && onSegment(c, d, a)) return true;
    if (d4 == 0 && onSegment(c, d, b)) return true;

    return false;
}
Each of those four lines is a separate verdict
  • Touching at an endpoint. One orientation is 0, so d1*d2 < 0 fails and the proper test answers no. Two paths meeting at a junction is a very natural thing for a statement to describe.
  • Collinear and overlapping. All four orientations are 0, and again the proper test answers no.
  • Collinear and disjoint. All four orientations are also 0 — so returning true whenever everything is collinear fails in the opposite direction. The onSegment calls are what tell these two apart.
  • A zero-length segment against another drops straight out of the onSegment branch.

The d1*d2 product is safe because orient already squashed to -1/0/1. Inline raw cross values there and you are multiplying two numbers near 8×1018.

The intersection point itself

Rarely asked, because it is rational rather than integral and the statement would then have to specify a tolerance. If you do need it, use the parameter form in long double:

// assumes the segments are known to intersect and are not parallel
long double t = (long double)cross(a, c, d) / cross2(b - a, d - c);
// point = a + t * (b - a)

Noticing that the answer is rational, and therefore probably not what is being asked for, is a useful reading habit by itself.

Drills: Kattis · Line Segment Intersection forces every degenerate case, including printing a segment when the overlap is a segment. Kattis · Line Segment Distance pairs with it.

Self-crossing walks

A common disguise: a path turns repeatedly and you must decide whether it ever re-crosses itself. These usually admit two solutions — an O(n²) all-pairs segment check, and a clever O(n) case analysis over consecutive turns.

Under a clock, write the O(n²) one unless n forbids it. The case analysis is short to read and easy to get subtly wrong, and you will have no reference model to check it against.


TIER B8 · Angular reasoning

The one place floating point is unavoidable. Worth learning because the ‘double the array’ trick transfers to every circular problem you will meet.

The shape of the question

You stand at a point with a field of view of θ degrees that you may aim anywhere, and you want the most you can see at once. Variants ask for the smallest angle covering everything, or the largest empty wedge. Same machine each time.

youanglesort the angles, append everyangle + 360°, then slide atwo-pointer window of widthequal to the field of view.Points sitting exactly on youhave no angle — count themseparately, always.
Convert each point to an angle, sort, then append every angle again with 360° added. A two-pointer window of fixed width on that doubled array is a rotating field of view, and the wrap-around needs no special handling.
int maxInWindow(vector<P>& pts, double angleDeg, P you) {
    vector<double> a;
    int same = 0;                                   // points exactly ON you
    for (P p : pts) {
        if (p.x == you.x && p.y == you.y) { same++; continue; }   // no angle exists
        a.push_back(atan2((double)(p.y - you.y), (double)(p.x - you.x)) * 180.0 / M_PI);
    }
    sort(a.begin(), a.end());
    int n = a.size();
    for (int i = 0; i < n; i++) a.push_back(a[i] + 360.0);   // the doubling

    int best = 0;
    for (int l = 0, r = 0; r < (int)a.size(); r++) {
        while (a[r] - a[l] > angleDeg + 1e-9) l++;   // EPS: boundary counts as inside
        best = max(best, r - l + 1);
    }
    return min(best, n) + same;
}
Three things that break this
  1. Points coincident with the observer. atan2(0,0) returns 0 instead of failing, which quietly files them at 0° and yields a wrong answer that clears the samples. They have no direction relative to you, so handle them outside the window entirely.
  2. The wrap-around. A window running from 350° to 10° is real, and the doubled array is what makes it cost no code.
  3. Epsilon direction. If a point exactly on the edge of the view counts as seen, the tolerance has to widen the window: > angle + 1e-9. Subtract instead of add and every tangency case fails. Read the boundary sentence, then aim the epsilon at it.
When to use an angle and when not to

Use atan2 only when you need the magnitude of an angle: a field of view, an arc, a difference between two directions.

Never use it to answer a comparison the cross product can answer. “Is C left of AB”, “are these directions the same” and “sort these points by angle around the origin” are exact integer questions, and routing them through atan2 converts an exact answer into an approximate one for nothing. Angular sorting is done with a half-plane bucket plus a cross product.

Drill: CF 257C · View Angle inverts the objective, and makes a good second rep once you have done a first.


TIER B10 · Polygons

Shoelace is cheap. Ray casting has one genuinely nasty edge case, and meeting it here costs less than meeting it in the hidden tests.

Shoelace

P02A = Σ cross(P0, Pi, Pi+1)Fan the polygon from any vertex.Triangles outside the shape get anegative sign and cancel exactly.Keep 2A. It is always an integerfor integer vertices. Halve last.
Fan the polygon into triangles from any single vertex and add the signed areas. Triangles protruding outside the shape come out negative and cancel the over-count exactly. Works for any simple polygon, convex or not.
long long twicePolygonArea(const vector<P>& v) {   // SIGNED: + is CCW, - is CW
    long long s = 0;
    int n = v.size();
    for (int i = 0; i < n; i++) {
        P a = v[i], b = v[(i+1) % n];
        s += a.x * b.y - a.y * b.x;                   // cross of the two position vectors
    }
    return s;                                         // abs() for area; sign for orientation
}

Two uses out of one function: llabs(s) is twice the area, and s > 0 says the vertices arrived counter-clockwise. Check that orientation before running anything that assumes a winding direction.

The accumulator, not the term

Each term is about 2C² and you are adding n of them. At C = 109 with n = 1000 the sum reaches 1021 and overflows long long even though no single term does. Either accumulate in __int128, or translate the polygon so its first vertex sits at the origin, which shrinks every term to the polygon's own extent. The translation is free and usually removes the problem outright.

Point in polygon

For a convex polygon, all consecutive cross products from the query point share a sign. Simple, exact, O(n).

For a general simple polygon, cast a ray (conventionally +x) and count crossings; odd means inside. The awkward part is a ray passing exactly through a vertex, which would otherwise be counted twice or not at all.

// returns true if p is strictly inside; boundary handled separately by onSegment
bool inPolygon(const vector<P>& v, P p) {
    int n = v.size(); bool in = false;
    for (int i = 0, j = n - 1; i < n; j = i++) {
        if (onSegment(v[j], v[i], p)) return true;         // boundary: decide your convention
        // the half-open y test is what makes vertices count exactly once
        bool straddles = (v[i].y > p.y) != (v[j].y > p.y);
        if (!straddles) continue;
        // x of the crossing, compared without dividing
        long long dx = v[j].x - v[i].x, dy = v[j].y - v[i].y;
        long long lhs = (p.y - v[i].y) * dx;
        long long rhs = (p.x - v[i].x) * dy;
        if (dy > 0 ? lhs > rhs : lhs < rhs) in = !in;      // flip comparison when dy is negative
    }
    return in;
}
Two load-bearing details
  1. (v[i].y > p.y) != (v[j].y > p.y) is a half-open test. An edge counts when it straddles the ray's height with one endpoint strictly above and one not-above. The asymmetry is deliberate: it assigns a vertex sitting exactly at the ray's height to exactly one of its two edges. Writing ≥ on both sides breaks it.
  2. Flipping the comparison when dy < 0. Cross-multiplying an inequality by a negative number reverses it. Omit the flip and the function is correct for roughly half the edges.

Drills with exact feedback: Kattis · Point in Polygon and Kattis · Polygon Area.


TIER C11 · Circles

Circles appear. Circle geometry mostly does not.

Every circle-flavoured problem in the company data reduces to comparing dist2 against r². Not one needs circle–circle intersection area, tangent lines, or a circumcircle. Keep everything squared and everything stays integral.

QuestionThe test
Is point P inside circle (C, r)?dist2(P,C) ≤ r*r
Do circles (A,r) and (B,s) overlap?dist2(A,B) ≤ (r+s)*(r+s)
Is one circle inside the other?dist2(A,B) ≤ (r-s)*(r-s), with r > s
Does circle (C,r) meet an axis-aligned rectangle?clamp C into the rectangle, then dist2(C, clamped) ≤ r*r

The last row deserves a second look, because the clamp is the nearest point:

// nearest point of an axis-aligned rectangle to a point
long long cx = max(r.x1, min(c.x, r.x2));
long long cy = max(r.y1, min(c.y, r.y2));
bool hit = (c.x-cx)*(c.x-cx) + (c.y-cy)*(c.y-cy) <= rad*rad;

No case analysis, and no separate handling for a centre that lies inside the rectangle.

A radius is usually an edge predicate

When a problem gives objects a range and asks what reaches what, the geometry is a one-line predicate and everything after it is a graph traversal. Build edges with dist2 ≤ r², then run whatever the question wants: reachability, components, shortest path.

Check whether the edge is directed. If each object carries its own radius, a long-range one can reach a short-range one without the reverse holding, and the relation is asymmetric. People lose these problems on the asymmetry rather than on the distance.


TIER C9 · Convex hull

Tier C, and I will be straight about why it is here at all: it appears in two problems across 25 company tag sets. It costs one evening, it is built entirely from §2, and it is the one advanced-sounding name that does turn up at Google.

The honest frequency

LC 587 · Erect the Fence — Google and Amazon. LC 1924 · Erect the Fence II — Google, premium, and it is minimum enclosing circle rather than hull. That is the complete list.

Learn it, do two problems, move on. Hull variants are not where your remaining hours belong.

leftmostlower hull, then upperSort by (x, y). Walk left→rightpopping while the last turn isnot a left turn. Then right→left.Interior points (grey) can neversurvive a pop test.
Andrew’s monotone chain. Sort by (x, y), build the lower hull left to right while popping any point that does not turn the right way, then the upper hull right to left. Two identical loops.
vector<P> convexHull(vector<P> p, bool keepCollinear) {
    sort(p.begin(), p.end(), [](P a, P b){
        return a.x != b.x ? a.x < b.x : a.y < b.y;
    });
    p.erase(unique(p.begin(), p.end(), [](P a, P b){
        return a.x == b.x && a.y == b.y;               // duplicates break the pop test
    }), p.end());
    if (p.size() < 3) return p;

    vector<P> h;
    for (int pass = 0; pass < 2; pass++) {              // lower, then upper
        size_t start = h.size();
        for (P q : p) {
            while (h.size() >= start + 2) {
                long long c = cross(h[h.size()-2], h[h.size()-1], q);
                if (keepCollinear ? (c < 0) : (c <= 0)) h.pop_back();
                else break;
            }
            h.push_back(q);
        }
        h.pop_back();                                   // last point starts the next pass
        reverse(p.begin(), p.end());
    }
    return h;
}
The only decision in this function

cross <= 0 pops collinear points and returns a hull of corners only. cross < 0 keeps them and returns every point on the boundary.

Which you want depends on the wording. A question about the shape — its area, its perimeter, how far it extends in some direction — wants corners. A question about which objects lie on the boundary wants all of them, since something sitting exactly on the boundary line is still on the boundary. Choose consciously each time rather than reusing whichever version you wrote last; getting this backwards is the one way to fail the function.

What a hull buys you

The Tier D boundary

These are real computational geometry and they sit outside your scope, because they appear zero times in the company data and near-zero in the OA-range Codeforces band: rotating calipers, half-plane intersection, Voronoi diagrams, Delaunay triangulation, k-d trees, Bentley–Ottmann, Minkowski sums, 3-D hulls, and the convex hull trick for DP optimisation, which is a DP technique that borrowed the name.

If an interviewer raises one, naming it and saying what it does beats a half-remembered implementation. Preparing them is the mistake this file exists to prevent.

Part III — recognition

The gap you named after the Oracle OA was not knowledge. You knew the cross product. You did not connect “is this a valid triangle” to it fast enough. That connection is a trainable reflex, and this is the drill for it.

The chain to run, every time

problem wording → geometric abstraction → primitive → algorithm → numeric type

Four worked examples of the chain, so the shape is concrete before you drill:

“are these three points a valid triangle?” → non-collinearity → cross product → one comparison against 0 → long long
“does this point lie on the road segment?” → collinear AND bounded → cross + bounding box → onSegment → long long
“do these two delivery paths cross?” → segment intersection → four orientations + four degeneracy checks → segIntersect → long long
“maximum distance among many points?” → farthest pair → READ n FIRST → n≤5000: brute force; n huge: hull → long long on dist2
The step people skip is the last one

Decide the numeric type while you are still recognising the problem. Defer it until you are typing and you will default to int and find out at the hidden tests. Say the type out loud when you name the primitive.

Twenty-four drills

No topic labels, deliberately mixed order. Commit to an answer before unlocking — a wrong guess that you then correct is worth more than a right guess you were not sure of, and far more than reading the answer first. Target: under ninety seconds each.

Answer first

1. “Given three vertices, determine whether they can form a triangle with positive area.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Cross product ≠ 0. Do not go near side lengths — you have coordinates, so collinearity is the question and it is exact.

Answer first

2. “You are given the lengths of n sticks. Can any three form a triangle?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Triangle inequality after sorting. No coordinates exist, so there is nothing for a cross product to act on. Sort and check adjacent triples — if any triple works, an adjacent one does. The twin of r1; do them as a pair.

Answer first

3. “A delivery drone travels between cells and may move diagonally. Minimum moves?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Chebyshev: max(|dx|, |dy|). ‘May move diagonally’ is the tell. 4-directional would be Manhattan.

Answer first

4. “Find the pair of servers with the smallest latency, where latency is Euclidean distance.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Squared distance. Then it is just a minimum over pairs — or divide and conquer if n is large. The word ‘Euclidean’ is not an instruction to call sqrt.

Answer first

5. “How many of the n antennas can be covered by rotating a directional beam of 45°?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Angular sliding window. atan2, sort, append +360, two pointers. Antennas at your exact position are always covered and must be counted separately.

Answer first

6. “Given m axis-aligned billboards, what total wall area do they cover?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Sweep + coordinate compression. Two billboards would be inclusion–exclusion; m of them makes that 2m terms, so you sweep one axis and measure covered length on the other.

Answer first

7. “Each sensor has a range r. Sensor A can trigger sensor B if B is within A’s range. How many fire if you trigger one?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

A graph problem with a dist2 ≤ r² edge predicate. The edge is directed — a long-range sensor reaches a short-range one without the reverse. Then DFS/BFS.

Answer first

8. “Determine the largest number of points that lie on a common straight line.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Canonical slope hashing. gcd-reduced pair, sign fixed, anchored at each point. double slope fails the official tests outright.

Answer first

9. “Two robots follow given paths. Do they ever occupy the same position?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Read the timing clause first. If they must be there simultaneously, it is simulation or a per-timestep comparison. If it merely asks whether the paths touch, it is segment intersection with every degenerate case live. These are different problems and the statement distinguishes them in one sentence.

Answer first

10. “Given start and end times of n jobs, find the minimum number of machines.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Event sweep. Maximum number of simultaneously alive intervals. Decide the touching convention from the statement before writing the comparator.

Answer first

11. “Find the smallest axis-aligned rectangle, with sides parallel to the axes, whose four corners are all in the given point set.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Hash set + iterate over diagonals. O(n²) pairs, check the two implied corners. The geometry is nil; the data structure is everything.

Answer first

12. “Determine whether a given point lies within a plot of land defined by its boundary vertices.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Point in polygon. Convex → consistent cross-product signs. General → ray casting with the half-open y test. And find the sentence about points on the boundary before you start.

Answer first

13. “A camera at the origin has a circular field of radius r. Does it see any part of the rectangular room?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Clamp the centre into the rectangle, then dist2 ≤ r². The clamped point is the nearest point of the rectangle. No case analysis needed.

Answer first

14. “Count pairs of points at equal distance from a given anchor.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Bucket by dist2, then k·(k−1)/2 per bucket (or k·(k−1) if the problem counts ordered pairs — check).

Answer first

15. “Given n line segments on a number line, find the point covered by the most of them.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

1-D sweep with a counter. This is the same machine as r10 with different nouns. Noticing recognising the repeat is the drill.

Answer first

16. “The minimum fencing needed to enclose all the trees.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Convex hull, then sum the edge lengths. ‘Enclose all’ plus ‘minimum perimeter’ is the hull’s defining property, and this phrasing is how it shows up.

Answer first

17. “Determine whether the polygon described by these vertices is convex.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

All consecutive cross products share one sign. Do not build a hull and compare — that is O(n log n) to answer an O(n) question, and the comparison itself is fiddly.

Answer first

18. “Maximise the number of points inside an axis-aligned square of fixed side k that you may place anywhere.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Sort by x, two-pointer window of width k, and within that window a second pass on y. A fixed-size box is two coupled sliding windows. If the square is rotated 45°, apply the Chebyshev rotation first.

Answer first

19. “Given n rectangles, is there a point covered by all of them?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Intersect the intervals on each axis independently. max(x1) ≤ min(x2) and the same for y. O(n), no sweep, no geometry.

Answer first

20. “Two players stand on a grid. Report the number of lattice points strictly between them on the straight line joining them.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

gcd(|dx|, |dy|) − 1. Number theory wearing a geometry costume. Worth knowing because it is short and because it is the kind of fact that unlocks an otherwise-hard problem instantly.

Answer first

21. “Given points, count triples that form a right angle at the middle point.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Dot product == 0, anchored at each candidate vertex. The dot product is the perpendicularity test the way the cross product is the collinearity test — the only place it earns its keep.

Answer first

22. “A signal travels outward from each tower at 1 unit/sec. When is the whole city covered?”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Binary search on the answer, with a geometric feasibility check at each candidate time. ‘When does X first become true’ plus a monotone predicate is always binary search; the geometry is only inside the predicate.

Answer first

23. “Find the maximum distance between any two of the n given points.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Read n first. n ≤ 5000 → brute force O(n²), and that is the intended answer far more often than people expect. Only at n ≥ 10⁵ does this become hull + rotating calipers — which is Tier D and essentially never asked.

Answer first

24. “Count how many of the given segments are parallel to each other.”

Name the primitive and the supporting algorithm. Out loud is fine. Then unlock.

Canonical direction key, then k·(k−1)/2 per bucket. Same machine as r8. If the question is about distinct lines rather than directions, extend the key to the full reduced (A,B,C).

Scoring yourself

Under 90 seconds and correct on 20 of 24 is the bar. Below 16, do not move on to the timed sets — go back to the Toolkit tab for the sections you missed, because a recognition failure under no time pressure becomes a blank page under a clock.

Parts V & VI — the problem set

Twenty-eight problems. Every one exists; none are invented; none carry a fabricated company attribution. Where a problem is a Codeforces or Kattis exercise rather than a reported company question, it says so in its row and explains what it trains.

How to run this table

Mode 1 — guided. Work down the table in order while reading the matching Toolkit section. The concept column is visible; that is intentional at this stage.

Mode 2 — recognition. Two days later, come back, cover the concept and technique columns with your hand, and re-derive which primitive each one needs from the title alone.

Mode 3 — mixed. The Timed tab. No labels at all.

Mode 5 — repair. If you fail the same concept twice, the Reference tab maps the failure back to a section and a three-problem repair set.

ProblemDifficultyGeometry conceptOther techniquesOA relevance & evidenceApproach
LC 973 · K Closest Points to OriginLC Mediumsquared distanceheap, quickselect, sortingTier A — 10/25 companies, max freq 77 (Meta)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The single most company-tagged geometry problem in existence. Do it to prove to yourself that the geometry is one line and the problem is a selection problem.

Sort or heap by x*x + y*y. Never sqrt. The O(n) move is nth_element / quickselect — worth writing once because interviewers ask for it after you give the heap answer.

LC 1266 · Minimum Time Visiting All PointsLC EasyChebyshev distancegreedyTier A — 6/25 companies, freq 86 (Media.net)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The cleanest possible demonstration that diagonal movement means Chebyshev, not Euclidean and not Manhattan. Media.net tags it at 86 — and Media.net is on your list.

With 8-directional movement, the time between two points is max(|dx|, |dy|): you burn the shorter axis for free while walking diagonally. Sum over consecutive pairs. If you find yourself writing |dx| + |dy| you have assumed 4-directional movement.

LC 1041 · Robot Bounded In CircleLC Mediumvectors, rotationsimulationTier B — widely tagged
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Disguised geometry with no coordinates in the statement. Trains the reflex of turning a described process into a vector.

Simulate one pass through the instructions. The robot is bounded iff it ends at the origin, or it ends facing a direction other than north — because a net rotation means four passes return it to the start. The second condition is the insight; the first is obvious.

LC 1037 · Valid BoomerangLC Easycross product—Tier A — Google, Microsoft
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Your Oracle OA, stripped to its core, in three points. Write it with cross and it is one line; write it with slopes and you will handle two special cases.

return cross(p[0], p[1], p[2]) != 0; Done. Note it rejects duplicate points automatically — two coincident points are collinear with anything.

LC 1232 · Check If It Is a Straight LineLC Easycollinearity—Tier A — Amazon
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The n-point version. Trains you to fix a reference pair once instead of comparing adjacent triples.

Fix the first two points as the line. Check cross(p[0], p[1], p[i]) == 0 for every other i. O(n), no division. Guard the case where p[0] == p[1] if duplicates are possible.

LC 812 · Largest Triangle AreaLC Easysigned areabrute forceTier A — Google, Bloomberg, Amazon
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The area half of the cross product, and a direct test of whether you resist dividing by 2 too early.

All O(n³) triples, take max of llabs(cross(a,b,c)), divide by 2.0 once at the end. n ≤ 50 so brute force is intended. Keeping 2×area integral until the final line is the habit being trained.

CF 6A · TriangleCF 900triangle inequality on lengthsbrute forceProxy — not an OA question
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Included because it is the lengths form of your Oracle problem, and doing both back to back is what fixes the ‘points → cross, lengths → inequality’ distinction.

Four sticks, try all triples. Non-degenerate needs a + b > c strictly; degenerate allows ==. There are no coordinates here, so the cross product has nothing to act on — that is the point of pairing it with LC 1037.

LC 149 · Max Points on a LineLC Hardcanonical slopehash mapTier A — 10/25 companies, max freq 56 (LinkedIn)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The second-most tagged geometry problem, and a 31% acceptance rate driven almost entirely by slope representation. If you do one problem from this file, do this one.

For each anchor point i, hash every other point by slopeKey(p[i], p[j]) and take the largest bucket, plus 1 for the anchor. O(n²). The gcd-reduced, sign-fixed pair is mandatory — double fails the official tests. Watch the vertical case (0, ±k).

LC 447 · Number of BoomerangsLC Mediumsquared-distance bucketshash map, combinatoricsTier A — Google, Bloomberg
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Teaches the ‘anchor, then bucket by an exact key, then count ordered pairs’ pattern that runs through half the point-set problems.

For each anchor, bucket the other points by dist2. A bucket of size k contributes k*(k-1) ordered pairs. Sum over anchors. Ordered, not unordered — the tuple (i,j,k) and (i,k,j) both count, which is why it is not divided by 2.

LC 593 · Valid SquareLC Mediumdistance multisetsortingTier A — TikTok, Google
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The sqrt-and-compare trap in its purest form, and a five-line solution once you stop reaching for floats.

Compute all 6 pairwise dist2, sort. A square is exactly: four equal smallest values, two equal largest, largest == 2 × smallest, and smallest > 0. The last clause rejects four coincident points, which is the test case that catches most solutions.

LC 2013 · Detect SquaresLC Mediumpoint counting by diagonalhash map, designTier A — Google, Amazon, Bloomberg, Meta
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: A design problem where the geometry is a filter. Four companies tag it, and the online-query shape is characteristic of modern OAs.

Store counts in map<pair<int,int>, int>. On query, iterate over stored points that form a diagonal with the query point — that is, |dx| == |dy| ≠ 0 — and multiply the counts of the two remaining corners. Iterating over candidate diagonals rather than all pairs is what keeps it fast.

LC 223 · Rectangle AreaLC Mediumrectangle overlap, inclusion–exclusion—Tier A — 6/25 companies, freq 52 (Nvidia)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The highest-frequency rectangle problem, and the only geometry problem in Microsoft’s recent six-month slice.

A + B − overlap, where overlap is max(0, min(x2) − max(x1)) × max(0, min(y2) − max(y1)). The max(0, ...) on each axis independently is the whole problem; multiplying two negatives gives a positive phantom overlap.

LC 836 · Rectangle OverlapLC Easyinterval overlap—Tier A — Microsoft, Amazon, Meta, Google
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Two characters of difficulty. Do it to burn the <-vs-≤ decision in.

max(x1) < min(x2) && max(y1) < min(y2). Strict, because this statement says touching does not count. Read that sentence every single time.

LC 939 · Minimum Area RectangleLC Mediumpoint set + rectanglehash setTier A — Flipkart (53), Google, Microsoft, Meta
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The canonical ‘find a shape inside a point set’ problem, and a good lesson in choosing which pair to iterate over.

Hash every point. For each pair with x1 ≠ x2 and y1 ≠ y2, treat it as a diagonal and check whether (x1,y2) and (x2,y1) both exist. O(n²). Grouping points by column first is the faster variant and worth knowing.

LC 963 · Minimum Area Rectangle IILC Mediumrotated rectanglehash map, dot productTier B — Google (35)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Removes the axis-aligned crutch. The key insight is a property of rectangles that has nothing to do with their orientation.

Two segments are the diagonals of a rectangle iff they share a midpoint and have equal length. Group every point pair by the key (x1+x2, y1+y2, dist2) — note the midpoint stored as a sum, never divided. Within each group, every pair of segments gives a rectangle; compute its area from the two side vectors.

LC 391 · Perfect RectangleLC Hardcorner parity + areahash set, sweepTier B — Google, Amazon, Meta
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The best example in the set of replacing a hard geometric verification with two cheap invariants.

Sum the areas; they must equal the bounding box’s area. Then toggle all four corners of every rectangle in a set — at the end exactly the four bounding-box corners must remain. Area alone permits a gap cancelled by an overlap; parity alone permits certain degenerate layouts. Together they are sufficient, and that is the thing to take away.

LC 56 · Merge IntervalsLC Medium1-D projectionsortingTier A — 21/25 companies, freq 93 (Zoho)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The most widely tagged problem in this entire file, geometry or not. You almost certainly can do it — do it anyway, from memory, and time yourself. It is the base case of every sweep.

Sort by start. Keep a current interval; if the next start is ≤ the current end, extend the end, else emit and restart. The ≤ is the touching convention and this problem wants touching intervals merged.

LC 253 · Meeting Rooms IILC Medium (premium)event sweepheap, sortingTier A — 17/25 companies, freq 84 (TikTok)
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The counter sweep, and the tie-break decision, in the form everyone asks for. If premium blocks you, LC 1851 · Minimum Interval to Include Each Query is the same algorithm with a public statement.

Two ways, both worth writing. (a) Event sweep: +1 at start, −1 at end, sort with ends first, track the running max. (b) Min-heap of end times: for each meeting in start order, pop every meeting that has already finished, then push. Heap size is the answer. Here a meeting ending at 10 does not conflict with one starting at 10.

LC 218 · The Skyline ProblemLC Hardsweep with a heapheap, sortingTier B — 8/25 companies
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The hardest problem in the Tier A/B set and the one that most rewards having a clean event model. Eight companies tag it, including Google, Meta, Microsoft and Amazon.

Events at every left and right edge. Sweep left to right keeping a multiset of active heights. When the maximum active height changes, emit a key point. The ordering rules at equal x are the entire difficulty: process all starts before all ends at the same x, sort starts by descending height and ends by ascending height. Write those three rules down before you code.

LC 850 · Rectangle Area IILC Hardsweep + coordinate compressionsortingTier B — Flipkart (60), Google
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The bridge from §5 to §7: many rectangles, one axis at a time.

Compress all y-coordinates. Sweep x; between consecutive x-events compute the total covered y-length by scanning the compressed strips that are currently covered, and add covered × Δx. O(n²) is fine at OA sizes — do not reach for a segment tree.

LC 1610 · Maximum Number of Visible PointsLC Hardangular windowtwo pointers, sortingTier B — Nvidia (68), Google, Amazon
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The one problem that justifies learning atan2, and the highest single frequency of any geometry Hard in the dataset.

atan2 for every point, sort, append every angle + 360, slide a two-pointer window of width angle. Add the count of points coincident with the observer at the end — they are always visible and have no angle. That coincident-point clause is the most common wrong answer.

CF 257C · View AngleCF 1800angular sortsortingProxy — trains LC 1610
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Same machinery, inverted objective: find the smallest angle that contains all points. Doing it right after 1610 is what turns the technique from ‘a solution I saw’ into ‘a thing I can do’.

Sort the angles. The answer is 360 minus the largest gap between consecutive angles (including the wrap-around gap from the last back to the first). One sort, one linear scan.

Kattis · Line Segment IntersectionKattissegment intersection—Proxy — trains §4 degeneracies
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The only exercise anywhere that forces every degenerate case, including printing an overlap segment when the answer is a segment rather than a point. There is no OA substitute for this.

Full orientation quadruple plus the four onSegment checks. For the collinear-overlap output, intersect the two bounding boxes and report the resulting sub-segment. If the boxes meet at one point, that point is the answer.

LC 335 · Self-CrossingLC Hardsegment intersection, disguisedcase analysisTier C — Bloomberg
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: A spiral walk that must decide whether it ever re-crosses itself. The statement contains the word ‘geometry’ nowhere.

Two legitimate routes. (a) Keep all segments and run pairwise segIntersect — O(n²), always correct, writable under pressure. (b) The O(n) three-case argument about shrinking and growing spirals — elegant and very easy to get wrong. In an OA, write (a). Knowing that (a) is acceptable is the real lesson.

LC 587 · Erect the FenceLC Hardconvex hullsortingTier C — Google, Amazon
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The only true convex-hull question in 25 company tag sets. One rep is the correct amount.

Andrew’s monotone chain. This problem wants all boundary points including collinear ones, so use cross < 0 in the pop test, not ≤. De-duplicate the output.

Kattis · Convex HullKattisconvex hull—Proxy — trains §9
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: Exact feedback on the collinear convention, and multiple test cases including n = 1 and n = 2, which is where hull implementations actually break.

Same function. Handle n < 3 before entering the loops. Kattis will tell you immediately if your collinear handling disagrees with theirs.

LC 1401 · Circle and Rectangle OverlappingLC Mediumcircle vs rectangle—Tier C — Google, Microsoft
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The clamp trick, which is the only circle technique the data justifies teaching.

Clamp the circle centre into the rectangle on each axis independently: cx = max(x1, min(c.x, x2)). That clamped point is the nearest point of the rectangle to the centre. Compare its dist2 to r*r. Four lines, no cases.

LC 2101 · Detonate the Maximum BombsLC Mediumcircle containment as a graph edgeDFS/BFS, graphTier B — Uber, Google, Amazon, Microsoft
Answer firstSolve it, or commit to an approach out loud, then unlock.

Why it is here: The archetype of what this whole research found: a one-line geometric predicate wrapped around an ordinary graph traversal.

Directed edge i→j iff dist2(i,j) ≤ rⁱ². Note it is directed and asymmetric. Then DFS from each node and take the largest reachable set. n ≤ 100 so O(n²) edges and n traversals are fine. Use long long: coordinates and radii reach 105, so r² reaches 1010.

Counts, and why they are what they are

ConceptProblemsReasoning
Cross product family6 (g4–g7, g10, g25)Tier A and it is the primitive everything else is built from. Repetition here pays into every other section.
Point-set hashing5 (g8–g11, g15)Two of the ten most-tagged geometry problems live here, and the failure mode (representation, not algorithm) needs several reps to stick.
Rectangles5 (g12–g16)The densest genuine-geometry cluster in the data.
Intervals and sweep4 (g17–g20)Highest frequency of anything in the file. Four rather than eight only because you already own the base case.
Distance and metrics3 (g1–g3)The idea is one line. Three problems is enough to make ‘never sqrt’ automatic.
Angular2 (g21, g22)One technique, one real problem, one proxy to prove it transferred.
Segments2 (g23, g24)Kattis forces the degeneracies better than any LeetCode problem; a third would be redundant.
Convex hull2 (g25, g26)Two problems is what the evidence supports. Not four.
Circles2 (g27, g28)Both reduce to dist2 vs r²; the second is really a graph problem, which is the lesson.
Where I deliberately under-trained

Convex hull gets two problems and circles get two, against six for the cross product. That is not laziness — it is the coverage matrix applied honestly. Hull appears in two problems across twenty-five companies. Giving it six would mean taking four away from the cross product, which appears in dozens. If the evidence changes, the allocation should.

Part VIII & X — timed sets and the final assessment

Real problems, realistic weight, no topic labels and no hints. The point is not whether you know the techniques — by now you do — but whether you can find them under a clock, which is the thing that actually went wrong in the De Shaw OA and in the Oracle one.

The rules, and they matter more than the problems
  • Close this file. All of it. No toolkit, no reference sheet, no editor autocomplete you would not have.
  • Write the primitives from memory as part of the clock. If you would paste them in an OA you cannot, so do not practise that way.
  • No brute-force stress testing during the clock — you will not have it. Afterwards, run toolkit/stress.py on anything you were unsure of. That habit is what turned CF 2264C around, and it belongs in the review, not the attempt.
  • Stop when the clock stops, even mid-thought. Score what you had. Knowing what your real 75-minute output looks like is what you came here to measure.

Set 1 — warm, but not easy

75 minutes · 4 problems · no hints, no topic labels
  1. LC 1266 · Minimum Time Visiting All Points
  2. LC 56 · Merge Intervals
  3. LC 939 · Minimum Area Rectangle
  4. LC 2101 · Detonate the Maximum Bombs
Answer firstFinish the set and score yourself before unlocking the note on it.

Two of these four are geometry by tag. Three are geometry in fact. Do not try to work out which — just solve them.

Set 2 — the hashing block

75 minutes · 4 problems · no hints, no topic labels
  1. LC 149 · Max Points on a Line
  2. LC 447 · Number of Boomerangs
  3. LC 253 · Meeting Rooms II
  4. LC 853 · Car Fleet
Answer firstFinish the set and score yourself before unlocking the note on it.

One of these is a stack problem that looks geometric. If you spend more than five minutes looking for a cross product in it, note that and move on.

Set 3 — full OA weight

90 minutes · 4 problems · no hints, no topic labels
  1. LC 223 · Rectangle Area
  2. LC 1610 · Maximum Number of Visible Points
  3. LC 11 · Container With Most Water
  4. LC 2013 · Detect Squares
Answer firstFinish the set and score yourself before unlocking the note on it.

This is the closest thing here to a real high-end OA: one easy, one hard with a subtle edge case, one classic, one design question.

Set 4 — the honest ceiling

90 minutes · 4 problems · no hints, no topic labels
  1. LC 218 · The Skyline Problem
  2. LC 587 · Erect the Fence
  3. LC 963 · Minimum Area Rectangle II
  4. LC 3025 · Find the Number of Ways to Place People I
Answer firstFinish the set and score yourself before unlocking the note on it.

Harder than most OAs will be. If you clear three of four inside 90 minutes, geometry is no longer a variable in your outcome.

Scoring — six axes, not one

“Solved / not solved” throws away the diagnosis. Score each problem out of 2 on each axis and write the numbers down; the pattern across four sets tells you what to repair.

Axis012
Recognitionnever saw the structurefound it after a wrong startnamed it in the first two minutes
Modellingwrong reductionright idea, wrong complexitycorrect and appropriately sized for n
Implementationdid not compile in timecompiled, failed samplesclean first pass
Correctnesswrong answerpassed samples, failed hiddenaccepted
Edge casesdid not consider anyconsidered, missed oneenumerated before coding
Timeover budgetat budgetunder with time to re-check
Reading your own scorecard

Recognition low, implementation high → the Recognition tab, not more problems. This is your documented pattern and the most likely result.

Recognition high, implementation low → you are typing too early. Enumerate the edge cases before the first line; this is the exact shape of the four bugs in your 2264C submission — the mathematics was right and the code was not.

Edge cases consistently 0–1 → the Edge cases tab, and run the battery against your own toolkit rather than reading it.

Time low everywhere else high → you are fine. Volume fixes this and nothing else does.

The standard, restated as a decision

Geometry has stopped being a variable in your OA outcome when, on Set 3 and Set 4 back to back on different days, you clear three of four inside the clock with recognition scored 2 on at least three problems per set. Anything less is not failure — it is a pointer to a section.

Part IX — how geometry solutions actually fail

Naive geometry code does not fail randomly. It fails in about a dozen specific ways, and every one of them has a two-line test case. Meeting them here is much cheaper than meeting them in the hidden tests.

The degenerate battery

Every one of these should be a test you run against your own from-memory toolkit. They are all in toolkit/selftest.cpp, which fails loudly and tells you which case broke.

CaseWhy it breaks thingsWhat must happen
Two coincident pointszero-length direction vector; gcd(0,0) = 0 then a division by itcross returns 0, onSegment is still correct, slopeKey guards the gcd
Three identical pointsevery derived quantity is zero at oncerejected as a triangle; not counted as a line of three points unless the statement says so
Zero-length segmentit is a point wearing a segment’s typesegIntersect handles it through the onSegment branch with no special case
Three collinear pointsthe ‘triangle’ has zero areacross == 0, rejected
Collinear overlapping segmentsall four orientations are 0, so the proper test says notrue, via onSegment
Collinear disjoint segmentsall four orientations are also 0false — this is why ‘all collinear → true’ is wrong
Segments touching at one endpointone orientation is 0, killing d1*d2 < 0true, via onSegment
Perfectly vertical linedy/dx divides by zeroslopeKey returns (0, 1)
Perfectly horizontal linesign normalisation can flip it inconsistentlyslopeKey returns (1, 0)
All-negative coordinatesabs forgotten; sign convention invertedidentical results to the translated-positive case
Coordinates at the constraint maximumthe overflow you did not run the ritual onno overflow, verified by the battery at 109
Point exactly on a triangle edge or at a vertexstrict-vs-inclusive ambiguitypointInTriangle returns 0, and you decide what 0 means for this statement
Rectangles sharing exactly one edge or corner< vs ≤matches the convention you chose, deliberately
Polygon with repeated or collinear verticesshoelace is fine; hull and containment are notshoelace exact; hull de-duplicates first
Points coincident with the observer (angular)atan2(0,0) silently returns 0counted separately and added to every window

Six wrong implementations, and the fix

1. The overflow that the return type does not fix

long long cross(P a, P b, P c) {          // x, y are int
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}

Every operation happens in int; the widening occurs after the damage. Fix: make the members long long. Not a cast at the call site — a cast you must remember is a cast you will forget.

2. The double slope

double slope = (double)(b.y - a.y) / (b.x - a.x);
mp[slope]++;                                  // LC 149, wrong answer
auto g = std::gcd(llabs(dx), llabs(dy));
if (g) { dx /= g; dy /= g; }
if (dx < 0 || (dx == 0 && dy < 0)) { dx = -dx; dy = -dy; }
mp[{dx, dy}]++;                               // exact

3. The collinear blindness in segment intersection

bool segIntersect(P a, P b, P c, P d) {
    return orient(a,b,c) * orient(a,b,d) < 0
        && orient(c,d,a) * orient(c,d,b) < 0;   // misses every touching and overlapping case
}

This is right for the generic case and wrong for four of the six configurations in the diagram back in §4. The four onSegment lines are not defensive coding; they are four distinct verdicts.

4. The triangle test that assumes counter-clockwise

bool inside(P a, P b, P c, P p) {
    return orient(a,b,p) > 0 && orient(b,c,p) > 0 && orient(c,a,p) > 0;
}

Correct for a counter-clockwise triangle, silently always-false for a clockwise one. Compare the three signs to each other, as in §3, or normalise the winding first.

5. The sweep whose tie-break was never chosen

sort(ev.begin(), ev.end());   // and no comment anywhere about what happens at equal x

Not wrong, just undecided — which works on the samples and then gets flipped back the first time one seems to disagree. Write the convention in a comment when you write the sort.

6. The epsilon pointing the wrong way

while (a[r] - a[l] > angle - 1e-9) l++;    // strict where the statement was permissive

LC 1610 says a point exactly on the edge of the field of view is visible, so the tolerance must widen the window, not narrow it: > angle + 1e-9. Read the boundary sentence, then point the epsilon at it deliberately.

Stress-test the degeneracies

The standing rule, applied to geometry

You already proved this works: the stress-test habit is what turned CF 2264C from three-plus submissions into one accepted on the first try. Geometry is the best subject for it, because a correct-but-slow reference is usually trivial — O(n³) over all triples, or a direct simulation — and the degenerate inputs that break geometry are exactly the ones a random generator produces when you restrict coordinates to a small range.

toolkit/stress.py is the harness. Generate coordinates in −3..3. Small ranges force collinearity, coincidence and tangency to appear within a few hundred cases; large random coordinates almost never produce a degenerate configuration, which is why stress-testing with big numbers finds nothing and feels reassuring.

# find a counterexample, smallest coordinates first
python toolkit/stress.py --fast ./sol --slow ./brute --gen ./gen.py --range 3 --n 6

Part XI — the sheet you should know by heart

Everything below should be reproducible from memory in under six minutes by the end of Week 1. Type it at the start of every session until that is true. It is about sixty lines and it is the entire toolkit.

using ll = long long;

struct P {
    ll x, y;                                          // ll HERE, not int
    bool operator<(const P& o) const { return x != o.x ? x < o.x : y < o.y; }
    bool operator==(const P& o) const { return x == o.x && y == o.y; }
};

ll cross(P a, P b, P c) {                             // (b-a) x (c-a)
    return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}
int orient(P a, P b, P c) { ll v = cross(a,b,c); return (v>0) - (v<0); }

ll dot  (P a, P b, P c) { return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y); }
ll dist2(P a, P b)      { ll dx=a.x-b.x, dy=a.y-b.y; return dx*dx + dy*dy; }

bool onSegment(P a, P b, P p) {                       // p on segment ab, inclusive
    if (cross(a,b,p) != 0) return false;
    return min(a.x,b.x) <= p.x && p.x <= max(a.x,b.x)
        && min(a.y,b.y) <= p.y && p.y <= max(a.y,b.y);
}

bool segIntersect(P a, P b, P c, P d) {
    int d1=orient(a,b,c), d2=orient(a,b,d), d3=orient(c,d,a), d4=orient(c,d,b);
    if (d1*d2 < 0 && d3*d4 < 0) return true;
    if (d1==0 && onSegment(a,b,c)) return true;
    if (d2==0 && onSegment(a,b,d)) return true;
    if (d3==0 && onSegment(c,d,a)) return true;
    if (d4==0 && onSegment(c,d,b)) return true;
    return false;
}

int pointInTriangle(P a, P b, P c, P p) {             // 1 in, 0 boundary, -1 out
    int d1=orient(a,b,p), d2=orient(b,c,p), d3=orient(c,a,p);
    bool neg = d1<0 || d2<0 || d3<0, pos = d1>0 || d2>0 || d3>0;
    if (neg && pos) return -1;
    if (!d1 || !d2 || !d3) return 0;
    return 1;
}

ll twicePolygonArea(const vector<P>& v) {             // signed: + is CCW
    ll s = 0; int n = v.size();
    for (int i = 0; i < n; i++) {
        P a = v[i], b = v[(i+1)%n];
        s += a.x*b.y - a.y*b.x;
    }
    return s;
}

pair<ll,ll> slopeKey(P a, P b) {
    ll dx = b.x-a.x, dy = b.y-a.y, g = std::gcd(llabs(dx), llabs(dy));
    if (g) { dx /= g; dy /= g; }
    if (dx < 0 || (dx == 0 && dy < 0)) { dx = -dx; dy = -dy; }
    return {dx, dy};
}

struct R { ll x1, y1, x2, y2; };
bool overlapArea(R a, R b) {                          // touching does NOT count
    return max(a.x1,b.x1) < min(a.x2,b.x2) && max(a.y1,b.y1) < min(a.y2,b.y2);
}
ll overlapAreaValue(R a, R b) {
    ll w = min(a.x2,b.x2)-max(a.x1,b.x1), h = min(a.y2,b.y2)-max(a.y1,b.y1);
    return (w>0 && h>0) ? w*h : 0;
}

vector<P> convexHull(vector<P> p) {
    sort(p.begin(), p.end());
    p.erase(unique(p.begin(), p.end()), p.end());
    if (p.size() < 3) return p;
    vector<P> h;
    for (int pass = 0; pass < 2; pass++) {
        size_t st = h.size();
        for (P q : p) {
            while (h.size() >= st+2 && cross(h[h.size()-2], h[h.size()-1], q) <= 0)
                h.pop_back();                          // <= drops collinear, < keeps them
            h.push_back(q);
        }
        h.pop_back();
        reverse(p.begin(), p.end());
    }
    return h;
}

The decision table — what to reach for

You see…Reach for§
“valid triangle” from pointscross != 03
“valid triangle” from lengthssort + triangle inequality3
“same line”, “collinear”, “straight”cross == 0 or slopeKey2, 6
“closest”, “within distance r”dist2 vs r*r1
“diagonal movement allowed”Chebyshev max(|dx|,|dy|)1
“4-directional”, “city blocks”Manhattan; solve each axis separately1
overlapping rectangles, 2 of theminterval overlap on both axes5
overlapping rectangles, manysweep + coordinate compression7
start/end times, meetings, jobsevent sweep with a counter7
“field of view”, “within an angle”atan2 + doubled window8
“enclose all”, “minimum fence”convex hull9
“area of the region”shoelace10
“inside the plot / region”point in polygon10
a radius creating a relation between objectsdist2 ≤ r² as a graph edge11
“maximum distance” and n ≤ 5000brute force O(n²) — genuinely9

Repair table — if you failed the standard

What went wrongIt is notGo toDo these three
Did not see the geometry at alla knowledge gapRecognition tab, all 24 drillsg4, g5, g28
Saw it, picked the wrong primitivea recognition gap — a mapping gapThe decision table aboveg7, g10, g14
Right primitive, wrong answerconceptualEdge cases tab + selftest.cppg13, g23, g21
Right answer, too slowgeometry at allRe-read n in the constraint line firstg6, g24, g20
Overflowedbad luckThe numeric ritual, §0g8, g12, g16
Could not write the toolkit from memorya reason to re-readType it daily for a weekthe sheet above, six minutes, timed
The maintenance protocol

Retention is your documented failure mode, not comprehension — most of those 109 hards were looked up and are not retrievable today. So:

Day 1 after finishing Week 1: type the sheet from memory, no reference. Diff it against toolkit/geo.hpp. Day 3: again, plus one Tier A problem cold. Day 10: again, plus Timed Set 2. Then two problems a week, forever, from memory, no reference.

Thirty minutes a week is what keeps twenty hours from evaporating. Skipping it is the only way this file becomes another unopened booklet.

Built 16 September 2026 from primary-source data pulled the same day: LeetCode's GraphQL problem API (4,055 public problems; 46 carry the geometry tag), 25 company tag sets from liquidslr/leetcode-company-wise-problems (snapshot 20 June 2025), the Codeforces problemset API (430 geometry-tagged problems), and Kattis. Every problem link was resolved against its source before being written down. This file is self-contained: no fonts, scripts, or images are loaded from anywhere else, so opening it tells nobody anything. Progress lives in your browser's localStorage. Print it for a PDF.