CSE3144 ยท Advanced Data Structures ยท Julโ€“Nov Semester 2026 ยท Lecture 12 of 36 ยท CO CSE3144.2

Segment Trees & Interval Trees

From "find one key" to "which of these ranges does my query touch?" Two different structures, two different assumptions about the data โ€” and today we build both, insert into both, query both, and trace every single step by hand.

Dr. Manu ShrivastavaCourse Instructor ยท Consultation Fri 2โ€“5 PM, LHC 308F
~70 minutesSession outcome: implement range and interval query operations
L12 ยท 00 โ€” Agenda ~70 min, longer than usual โ€” the topic earns it

Today, part by part

Why segment trees? The stabbing-query problem

00โ€“03

Machine-busy intervals, IP router filters, VLSI masks โ€” "which intervals touch this point?"

Segment tree definition: elementary intervals

03โ€“06

A binary tree over a fixed range, splitting recursively down to unit intervals.

Animation: building the tree for [1,13]

06โ€“11

Every level of the split, until every leaf is a unit interval.

Canonical decomposition & the insert rule

11โ€“15

Why any interval lands in at most O(log n) nodes โ€” the key property.

Animation: insert [3,11] โ€” every recursive call

15โ€“23

Ten node visits, not one skipped โ€” including the ones that store nothing.

Animation: insert [4,10] โ€” a cleaner cover

23โ€“27

Same rule, boundaries that align with the tree โ€” half the nodes needed.

Animation: query [5,6] โ€” reporting stored intervals

27โ€“32

Walk the unique root-to-leaf path; collect everything stored along it.

Animation: delete [4,10]

32โ€“35

The same recursive path, removing instead of storing.

Segment tree complexity, recap

35โ€“37

Build, insert, delete, query โ€” one table.

Why interval trees? The dynamic, unbounded case

37โ€“40

Calendars, genomes, network events โ€” no fixed integer universe in sight.

Interval tree definition & the overlap condition

40โ€“44

An augmented BST ordered by low endpoint, plus a max_high at every node.

Animation: build the interval tree, 6 insertions

44โ€“53

Every comparison, every placement, every max update โ€” even the ones that don't change anything.

Animation: overlap search for [14,16]

53โ€“59

Report all four overlaps โ€” and watch one whole subtree get pruned for free.

Point query vs. range query โ€” what overlap search really asks

59โ€“62

Why [14,16] is a genuinely different question from the segment tree's [5,6], not just a bigger version of it.

Interval tree complexity, then the two structures compared

62โ€“66

Same overlap problem, two different assumptions about the data.

Recap & what's next

66โ€“70

Lecture 13: Tries and Digital Search Trees.

CSE3144 โ€” Lecture 12
L12 ยท 01 โ€” Why segment trees? ~3 min

The question no BST answers well: "what touches this point?"

The stabbing query

Suppose n machines are each busy during some integer time interval โ€” machine A from minute 15 to 20, machine B from 10 to 30, and so on. A scheduler constantly asks: "which machines are busy during minute [2,3]?" โ€” a single point (or unit interval) "stabbing" through a set of ranges.

A plain BST indexes single values, not ranges โ€” it has no natural notion of "does my point fall inside this stored interval?" Scanning all n intervals per query is O(n). With thousands of intervals and thousands of queries, that's too slow.

Where this shows up
  • IP router filters: a firewall rule like (10*, [20,60]) matches a rectangle of address space โ€” deciding which rules match a packet is a stabbing query.
  • VLSI mask verification / motion tracking: computational geometry problems reduce to "which segments does this sweep-line touch right now?"
  • Genome / calendar / network-event systems: "which recorded intervals overlap this instant?" โ€” the same question, different domain.

A segment tree answers this in O(log n + k), where k is the number of intervals reported โ€” by pre-organizing the integer universe itself, once, into a fixed hierarchy of ranges.

CSE3144 โ€” Lecture 12
L12 ยท 02 โ€” Segment tree: the definition ~3 min

A binary tree over the number line itself, not over the data

The recursive structure
  • Every node v represents a closed range [s(v), e(v)] with s(v) < e(v), both integers.
  • The root represents the whole universe, [1, n].
  • If e(v) = s(v) + 1, v is a leaf โ€” a unit interval, [k, k+1]. It splits no further.
  • Otherwise, split at the midpoint m = โŒŠ(s(v)+e(v))/2โŒ‹: left child = [s(v), m], right child = [m, e(v)].
The key mental shift

Notice what's fixed before you insert a single interval: the entire tree shape depends only on the universe size n โ€” not on which intervals you'll eventually store. You build the skeleton once; then you decorate nodes of that skeleton with whichever intervals fall inside them. This is completely different from a BST, where the shape depends on the data itself.

Every unit interval [k, k+1] is called an elementary interval โ€” these are the leaves. Height of this tree for [1, n] is at most โŒˆlogโ‚‚(n โˆ’ 1)โŒ‰ + 1, so any root-to-leaf walk is O(log n) โ€” exactly like a balanced BST, but the balance is guaranteed by construction, never by rotation.

CSE3144 โ€” Lecture 12 ยท Segment tree definition
L12 ยท 03 โ€” Animation: building the tree ~5 min

Root range [1,13] โ€” split until every leaf is a unit interval

Why 13, and why it looks slightly uneven

n = 13 is not a power of 2, so the tree isn't perfectly complete โ€” some branches hit unit length one level sooner than others. That's normal and doesn't break anything: the height bound โŒˆlogโ‚‚12โŒ‰ + 1 = 5 still holds everywhere.

How to read the animation

Teal boxes still have children (they split further). Amber boxes are leaves โ€” unit intervals, done splitting. Watch the tree reveal one full level at a time.

Interactive โ€” reveal the tree level by level
CSE3144 โ€” Lecture 12 ยท Segment tree build
L12 ยท 04 โ€” Canonical decomposition ~4 min

Storing an interval: cover it with the fewest possible nodes

The insert rule
insert(s, e, v):
  // store [s,e] into the subtree rooted at v
  if s <= s(v) and e(v) <= e:
      add [s,e] to v            // v's whole range fits inside [s,e]
      // stop โ€” do NOT recurse into v's children
  else:
      m = (s(v) + e(v)) / 2
      if s < m:  insert(s, e, v.left)
      if e > m:  insert(s, e, v.right)
Three properties this guarantees
  • If [i,j] is stored at node v, it is never also stored at any ancestor or sibling of v โ€” no duplication, no double-reporting.
  • At any single level of the tree, [i,j] is stored in at most 2 nodes.
  • Since the tree has O(log n) levels, every interval is stored in O(log n) nodes total โ€” this set of nodes is called its canonical decomposition.
The condition, on a number line โ€” same [3,11] you'll watch get inserted next slide
insert [3,11]
node [4,7]

[4,7] sits entirely inside [3,11] โ€” 3 โ‰ค 4 and 7 โ‰ค 11, both hold. Store [3,11] at this node, stop โ€” no need to recurse, every point in [4,7] is genuinely covered.

insert [3,11]
node [1,13]

[1,13] pokes out on both sides of [3,11] โ€” the test needs 3 โ‰ค 1, which fails immediately. Do NOT store [3,11] here: storing it would wrongly claim positions 1โ€“3 and 11โ€“13 are covered too. Recurse into the children instead.

The else case โ€” which child(ren)? Split node [1,13] at its own midpoint m = (1+13)/2 = 7, then ask the same question of each half separately:

node [1,13]
insert [3,11]
m = 7
  • Left half is [1,7]. s = 3 < m = 7 โ†’ the interval reaches left of the midpoint โ†’ recurse into v.left.
  • Right half is [7,13]. e = 11 > m = 7 โ†’ the interval reaches right of the midpoint too โ†’ recurse into v.right.
  • Both tests pass here, so both children get visited โ€” exactly the first step of the [3,11] trace on the next slide. (Had the interval stopped short of 7 on one side, only the child on that side would ever be called โ€” that's how the recursion avoids wasted work.)

Each node holds 0 or more stored intervals โ€” most nodes will hold none; a handful will hold one or two. The next two animations trace this insert rule literally, call by call, for two different intervals over the tree we just built.

CSE3144 โ€” Lecture 12 ยท Canonical decomposition
L12 ยท 05 โ€” Animation: insert [3,11] ~8 min

Every recursive call, including the ones that store nothing

We call insert(3, 11, root). Ten nodes get visited before the recursion bottoms out everywhere. Watch the two-part test โ€” "does s โ‰ค s(v) and e(v) โ‰ค e?" โ€” get evaluated with real numbers at every single one, even the visits that lead nowhere. Back to L12ยท01's scheduling story: [3,11] is Machine A, busy from minute 3 to minute 11 โ€” keep that mapping in mind for the query and delete slides ahead.

Interactive โ€” trace insert(3, 11) node by node
CSE3144 โ€” Lecture 12 ยท Insert [3,11]
L12 ยท 06 โ€” Animation: insert [4,10] ~4 min

Same rule, a boundary that lines up with the tree

[4,10]'s endpoints happen to be existing split points in the tree, so its canonical decomposition needs only 2 nodes instead of 4 โ€” and both of them already hold [3,11] from the last insertion. Watch a node accumulate its second stored interval. In machine terms: [4,10] is Machine B, busy from minute 4 to minute 10 โ€” its window sits entirely inside Machine A's, which is exactly why every node that stores B also already stores A.

Interactive โ€” trace insert(4, 10) node by node
CSE3144 โ€” Lecture 12 ยท Insert [4,10]
L12 ยท 07 โ€” Animation: query [5,6] ~5 min

One unique path from root to leaf โ€” collect everything stored on it

Why this works

A unit interval like [5,6] corresponds to exactly one leaf, and a tree has exactly one path from root to any leaf. Any interval whose canonical decomposition includes a node on that path necessarily overlaps [5,6] โ€” and by the "no duplication" property, nothing is ever reported twice.

What to expect

Both [3,11] (Machine A) and [4,10] (Machine B) happen to be canonically stored at node [4,7] โ€” which sits directly on the path to leaf [5,6]. So this single query should report both machines as busy at minute 5, from that one stop, and nothing else.

What "query [5,6]" means, and how each step decides left vs. right

This is another stabbing query โ€” the same question as L12ยท01's "which machines are busy at minute [2,3]?" [5,6] is just how this tree names the single point 5: every unit interval [k,k+1] is a leaf (L12ยท02), so asking "what covers position 5?" means walking down to leaf [5,6] and collecting everything stored along the way.

The decision rule is the same midpoint test as insert's else-branch: at each node, compute mid = (s(v)+e(v))/2; if 5 < mid, go left; if 5 โ‰ฅ mid, go right. Nothing new โ€” it's the identical comparison that just decided v.left vs v.right for [3,11] on the canonical-decomposition slide.

What's genuinely different from insert: insert checks s < m and e > m separately, because a wide interval can straddle the midpoint and need both children. A query like [5,6] is only one unit wide โ€” it can never straddle a midpoint, so exactly one of those two conditions ever holds. That's why this walk never branches: one single root-to-leaf path, never two โ€” the whole reason a query is cheap.

The whole rule, done at every single node, in this order:

  • 1. Report: whatever this node stores โ€” add it to the answer. This has nothing to do with left/right; it happens whether you go on to branch or not.
  • 2. Branch โ€” only if this node isn't the target leaf yet: mid = โŒŠ(s+e)/2โŒ‹; if 5 < mid, go left; otherwise, go right.
  • 3. Stop once e = s+1 โ€” that node is leaf [5,6], and the walk is over.

That's it โ€” the same three-line checklist, five times in a row below. Nothing changes step to step except the numbers.

Interactive โ€” walk the path to leaf [5,6]
CSE3144 โ€” Lecture 12 ยท Query [5,6]
L12 ยท 08 โ€” Animation: delete [4,10] ~3 min

Same recursion, remove instead of store

delete(4,10,v) follows exactly the same branching we just traced for insert(4,10,v) โ€” same covered-check, same mid comparisons, node for node. The only difference is the action taken when a node's range is fully covered: remove the interval from its stored set instead of adding it. In the scheduling story: Machine B ([4,10]) has finished its job and leaves the tree; Machine A ([3,11]) stays behind, untouched. The animation below walks all 5 visited nodes one at a time, exactly like the insert trace did โ€” nothing skipped.

Interactive โ€” trace delete(4, 10) node by node
CSE3144 โ€” Lecture 12 ยท Delete [4,10]
L12 ยท 09 โ€” Segment tree: complexity recap ~2 min

One structure, four costs

OperationCostWhy
Build the skeleton (universe [1,n])O(n)One-time; total nodes = 2ยท(number of leaves) โˆ’ 1, all created up front.
Insert an intervalO(log n)Canonical decomposition touches O(log n) nodes โ€” verified: 10 visits, 4 stores, for [3,11].
Delete an intervalO(log n)Identical recursion to insert.
Stabbing query [a,a+1]O(log n + k)One root-to-leaf path (O(log n)), reporting k stored intervals found on it.
CSE3144 โ€” Lecture 12 ยท Segment tree complexity
L12 ยท 10 โ€” Why interval trees? ~3 min

What if there's no fixed universe [1,n] to pre-split?

Where segment trees start to strain

A segment tree needs the whole integer range known in advance โ€” build once over [1,n], then insert intervals into it. But real scheduling data rarely looks like that: meeting times are real-valued and span years; genome coordinates run into the billions; network events arrive with no known upper bound. Rebuilding a segment tree's skeleton every time the universe changes is wasteful, or simply impossible if it's unbounded.

The interval tree idea

Stop indexing the number line. Index the intervals themselves, directly, the way a BST indexes keys โ€” ordered by their low endpoint โ€” and augment every node with one extra number: the largest high endpoint anywhere in its subtree. That single number is enough to search, insert, and delete in O(log n), fully dynamically, with no universe size fixed in advance.

Real uses: calendar/meeting-room scheduling, overlapping-gene detection in genome analysis, network event simulation.

CSE3144 โ€” Lecture 12
L12 ยท 11 โ€” Interval tree: definition & overlap ~4 min

An augmented BST, ordered by low endpoint

What every node stores
  • Its own interval, [low, high].
  • max โ€” the largest high endpoint anywhere in the subtree rooted here (itself included).

BST ordering is by low value only. The underlying tree can be a plain BST, or a self-balancing one โ€” we'll use an AVL tree (Lectures 7โ€“9) as the skeleton, since you've already mastered its rotations. The genuinely new machinery today is the max augmentation, not rebalancing.

The overlap condition

Intervals [a,b] and [c,d] overlap exactly when a โ‰ค d and c โ‰ค b โ€” equivalently, "neither one ends before the other begins."

[5,15]
[10,20]

Overlapping: 5 โ‰ค 20 and 10 โ‰ค 15 โ€” both hold.

[3,9]
[13,20]

Not overlapping: 3 โ‰ค 20 holds, but 13 โ‰ค 9 fails โ€” [3,9] ends before [13,20] begins.

CSE3144 โ€” Lecture 12 ยท Interval tree definition
L12 ยท 12 โ€” Animation: building the interval tree ~9 min

Insert (15,20), (10,30), (17,19), (5,20), (12,15), (30,40) โ€” one at a time

What every insertion actually does
  1. Descend by comparing low values, exactly like an ordinary BST insert.
  2. Place the new node as a leaf; its own max starts equal to its own high.
  3. Walk back up the same path to the root, and at every ancestor recompute max = the largest of: its own high, its left child's max (if any), its right child's max (if any).
Watch for the "nothing changed" steps

Most of the max-update steps below will report no change โ€” the new value simply wasn't the largest one already known at that ancestor. That's just as important to see as the steps where max does change: it's the reason this update only ever costs O(depth), never more.

Interactive โ€” every comparison, placement, and max update
CSE3144 โ€” Lecture 12 ยท Interval tree build
L12 ยท 13 โ€” Animation: overlap search for [14,16] ~6 min

Report every overlap โ€” and prune whatever can't possibly match

The search rule at every node v
findOverlaps(v, i):
  if v is null: return
  if overlap(v.interval, i): report v.interval
  if v.left exists and v.left.max >= low(i):
      findOverlaps(v.left, i)
  if v.right exists and low(v) <= high(i):
      findOverlaps(v.right, i)
Why the pruning is safe

v.left.max is the largest high endpoint anywhere in the left subtree. If even that largest value is smaller than low(i), nothing in the left subtree can overlap i โ€” skip it entirely, without visiting a single node inside it. That's the entire payoff of the max augmentation.

Interactive โ€” trace findOverlaps(root, [14,16])
CSE3144 โ€” Lecture 12 ยท Overlap search
L12 ยท 14 โ€” Point query vs. range query ~3 min

Why [14,16] is a genuinely different question from [5,6]

The segment tree's question โ€” a snapshot

query [5,6] asked: "who's busy at this one instant โ€” minute 5?" A single point in time. The answer is whichever machines happen to be running right then, and only them.

The interval tree's question โ€” a window

findOverlaps(root, [14,16]) asks something broader: "who's busy at any point during this whole 2-minute window?" Not an instant โ€” a span. A machine doesn't need to be running for the whole window, or even most of it โ€” sharing a single minute with the query is enough to count.

Checked against all six machines from the build animation
Machine's busy windowOverlaps [14,16]?Reported?
[15,20]Yes โ€” running through 15, 16โœ“
[10,30]Yes โ€” the whole window sits inside its scheduleโœ“
[5,20]Yes โ€” running through 14, 15, 16โœ“
[12,15]Yes โ€” shares just minute 14 with the windowโœ“
[17,19]No โ€” doesn't start until minute 17โœ—
[30,40]No โ€” doesn't start until minute 30 (pruned, never even checked)โœ—

Notice [12,15] makes the list despite overlapping the window by a single minute โ€” that's the whole point of a range query. Tying back to L12ยท10's motivation: "who's busy right now" is a point question, but "does this new 2pmโ€“3pm meeting conflict with anything already on the calendar?" is a range question โ€” you're not asking about one instant, you're asking whether a whole proposed window collides with any existing booking. That is the real question interval trees are built to answer.

CSE3144 โ€” Lecture 12
L12 ยท 15 โ€” Interval tree: complexity, then head-to-head ~4 min

Same problem, two different assumptions about the data

OperationCost
InsertO(log n)
DeleteO(log n)
Overlap search (one match)O(log n)
Overlap search (report all k matches)O(log n + k)
AspectSegment treeInterval tree
What's indexedThe number line [1,n] itselfThe set of intervals directly
Needs a known universe size?Yes โ€” built once over [1,n]No โ€” works over any real-valued domain
Underlying shapeFixed by n, never rebalancedA balanced BST (AVL/Red-Black) by low endpoint
Best query typeStabbing query โ€” a single point/unit rangeOverlap query โ€” against any interval, any size
Query costO(log n + k)O(log n) for one match, O(log n + k) for all
Typical useFixed discretized domains: pixel rows, router filters, time slotsDynamic real-valued domains: calendars, genomes, network events
CSE3144 โ€” Lecture 12 ยท Comparison
L12 ยท 16 โ€” Recap & what's next ~4 min

Two structures, one underlying question

Lecture 13 โ€” next

Tries and Digital Search Trees

Apply prefix searching and dictionary operations โ€” indexing by the shape of the key itself, not by comparison.

Homework โ€” bring to Lecture 13
  • Build the segment tree for universe [1,9]. How many leaves, how many total nodes, and what height does the formula predict?
  • On that tree, trace insert(2,7) node by node, listing every stored node exactly as we did for [3,11].
  • Insert (2,6), (1,4), (9,15), (5,8) into an interval tree in that order. Draw the final tree with every node's max value.
  • Using the interval tree built in this lecture, trace findOverlaps for the query [25,35]. Which nodes get pruned, and why?
  • In 3โ€“4 sentences: why can't a segment tree be used directly for real-valued (non-integer) intervals without modification?
  • Reading: de Berg et al., Computational Geometry, Ch. 10 (segment trees) & Ch. 14 (interval trees); CLRS ยง14.3 (interval trees).
CSE3144 โ€” Lecture 12

Questions?

Dr. Manu Shrivastava โ€” LHC 308F โ€” Friday 2:00โ€“5:00 PM

Next: Lecture 13 โ€” Tries and Digital Search Trees.