Skip to content

Segment Tree and Fenwick Tree

advanced · 35 min · Last reviewed 31 Oct 2026 · by TheLearningLoop Team

Key takeaways

  • A prefix array has fast queries and slow updates, a plain array the reverse. Fenwick and segment trees make both O(log n) by storing partial results for ranges of different sizes.
  • A Fenwick tree cell i holds the sum of the last lowbit(i) positions ending at i. Updates jump forward by lowbit, queries jump backward by it.
  • A Fenwick tree needs an operation you can undo, such as a sum. For range minimum or maximum, or for range updates, use a segment tree.

New to this topic? Read the overview first: Data Structures & Algorithms: The Big Picture

When to use a Fenwick tree or a segment tree

Use a Fenwick tree (binary indexed tree) when you need:

  • Range sums (or counts) on an array whose values change, such as a live leaderboard or a running total of sales per hour.
  • To count how many items are smaller than a given value as items arrive (counting inversions).
  • A structure that is tiny to write: about 15 lines and one array.

Use a segment tree when you need:

  • Range minimum, maximum, gcd or any combining operation that is not a plain sum, on an array that changes.
  • Range updates, such as "add 5 to every value from position 3 to 9", using lazy propagation.
  • Questions such as "the first position where the prefix sum passes X", answered by walking down the tree.

Use something else when:

  • The array never changes: use prefix sums for sums (O(1) per query) or a sparse table for min and max (O(1) per query).
  • You query one position only: a plain array is enough.
  • The data lives in a database: its index already does this.

Do not write your own in production unless you must. Most languages have no built-in version (see the real-world section). In interviews and contests you will write one by hand.

How Fenwick and segment trees work

Both answer the question "what is the combined value of this range?" in O(log n) and apply a change in O(log n). A plain array makes one of those fast and the other slow. A prefix sum array answers a range in O(1) but a change rewrites up to n cells. A plain array applies a change in O(1) but a range costs O(n).

Both trees split the difference by storing partial sums that cover ranges of different sizes:

A tree stores sums of ranges whose sizes are powers of two, so any range is the union of about log n of them, and any one change touches only about log n of them.

  • A Fenwick tree keeps one array. Cell i holds the sum of the last lowbit(i) positions ending at i, where lowbit(i) is the lowest set bit of i (i & -i). For example cell 4 covers positions 1 to 4, and cell 6 covers positions 5 to 6.

    Here is lowbit for the eight cells in this lesson. The lowest set bit is the rightmost 1 in the binary form.

    CellBinarylowbitPositions covered
    100111
    201021 to 2
    301113
    410041 to 4
    510115
    611025 to 6
    711117
    8100081 to 8

    To sum positions 1 to 7, write 7 as 111. Take cell 7 (covers 7), remove the lowest bit to get 110 = 6 (covers 5 to 6), remove it again to get 100 = 4 (covers 1 to 4), then 000 = 0 stops. The cells are 7, 6 and 4, and together they cover positions 1 to 7 exactly once.

  • A segment tree keeps a binary tree. Each leaf is one value. Each parent stores the combined value of its two children, so the root covers everything. In the usual array layout, the children of node i are 2i and 2i + 1. The version in the simulation is the bottom-up layout: for n values the leaves sit at cells n to 2n - 1 (value number p, counting from 0, is at cell n + p), the internal nodes are cells 1 to n - 1, and the array has 2n cells. The simpler top-down recursive version needs up to 4n cells when n is not a power of two, which is why you will see both "2n" and "4n" quoted.

Try it

Choose a structure and an operation sequence. The array has eight values, positions 1 to 8.

Segment Tree and Fenwick Tree

Step 1 of 9 · Press Space to play, arrow keys to step

Values (positions 1 to 8 are cells 0 to 7)

Fenwick tree (cell i covers the last lowbit(i) positions ending at i; cell 0 unused)

Initial state. Cell i of a Fenwick tree stores the sum of the last lowbit(i) values ending at position i. For example cell 4 covers positions 1 to 4, and cell 6 covers positions 5 to 6.

step:
0
cells touched:
0

Things to try:

  • Run the Prefix sum array with Only the query. It touches 2 cells, the cheapest of the three. Then choose Add 5 to position 3, then the same query: the update rewrites 6 cells (positions 3 to 8), 8 cells in all.
  • Run the Fenwick tree with the same two operations. The update touches 3 cells (3, then 4, then 8) and the query 4 cells, 7 in all. With only 8 values the saving is small. The prefix array's update cost grows with n, while the Fenwick tree's grows with log n.
  • Run the Segment tree and watch the update climb from the leaf to the root, one cell per level (4 cells), then the query pick a few whole segments (4 more).

Fenwick and segment tree operations: update, prefix and range

Fenwick update at position i by delta. Add delta to cell i, then move to i + lowbit(i) and repeat while i is within the array.

Fenwick prefix sum of positions 1 to i. Add cell i, then move to i - lowbit(i) and repeat while i is above 0.

Fenwick range sum l to r. Compute prefix(r) - prefix(l - 1). This only works because sums can be subtracted.

Segment tree update. Change the leaf, then walk up to the root, recomputing each parent from its two children.

Segment tree range query. Start with the two ends of the range at the leaf level. At each level, if the left end is a right child, include that node and move right; if the right end is a right child, step left and include that node; then move both ends up one level. Only whole segments are added, never single values.

In pseudocode, for the half-open range [l, r) (it includes l and stops before r), with 0-based values:

query(l, r):
    l = l + n
    r = r + n
    result = identity            # 0 for sum
    while l < r:
        if l is odd:  result = combine(result, t[l]); l = l + 1
        if r is odd:  r = r - 1; result = combine(result, t[r])
        l = l / 2
        r = r / 2
    return result

Worked query. Take the values after the update in the simulation: 3 2 10 1 4 6 2 8, so n = 8 and value number p is at cell 8 + p. We want positions 2 to 7, which are values number 1 to 6, so the half-open range is [1, 7).

  1. l = 9, r = 15. l is odd: add cell 9 (value 2), l = 10. r is odd: r = 14, add cell 14 (value 2). Halve: l = 5, r = 7.
  2. l = 5 is odd: add cell 5, which is cell 10 + cell 11 = 10 + 1 = 11, then l = 6. r = 7 is odd: r = 6, add cell 6, which is cell 12 + cell 13 = 4 + 6 = 10. Halve: l = 3, r = 3.
  3. l is no longer below r, so stop. The total is 2 + 2 + 11 + 10 = 25, the same answer as the Fenwick tree, using four whole segments.

Because the two ends are combined in the order they are met, the bottom-up query is only correct for operations where order does not matter (commutative ones such as sum, min, max and gcd). For an order-sensitive operation, such as joining strings, keep a separate left result and right result.

Lazy propagation (range update). Suppose we must add 5 to every value in positions 3 to 9, and there may be thousands of positions. Changing every leaf costs O(n). Instead, find the few whole nodes that cover the range, as in a query. For each such node, add 5 × (number of positions it covers) to its stored sum, and write a tag on it that says "5 is still owed to every position below you". Nothing below is touched yet. Then recompute the ancestors of those nodes on the way up.

Later, a query or update needs to look inside a tagged node. Before going down, do a push-down: add the tag to each child (child sum grows by 5 × its size, and the child gets or adds to its own tag), then clear the parent's tag. Now the children are correct and the work moves down only one level at a time, along one path. Each range update and each range query still touches O(log n) nodes. The cost is one extra array for the tags and care with the order: always push down before you read or change a child.

A plain sum Fenwick tree cannot do range minimum or maximum, because you cannot subtract a minimum. This is the interview fact, and it is the main reason to choose a segment tree. The wording matters: a Fenwick tree can answer a prefix maximum if values only ever increase, but an arbitrary range minimum or maximum with changing values needs a segment tree.

Dry run: update and prefix on the Fenwick tree

Start with the values 3 2 5 1 4 6 2 8 from the simulation. After building, the Fenwick cells 1 to 8 are 3 5 5 11 4 10 2 31. For example cell 4 = 3 + 2 + 5 + 1 = 11, and cell 6 = 4 + 6 = 10.

update(3, +5). Start at 3. Cell 3 becomes 5 + 5 = 10. Then 3 + lowbit(3) = 3 + 1 = 4. Cell 4 becomes 11 + 5 = 16. Then 4 + 4 = 8. Cell 8 becomes 31 + 5 = 36. Then 8 + 8 = 16, which is past the end, so stop. Three cells changed: 3, 4 and 8. The cells are now 3 5 10 16 4 10 2 36.

prefix(7). Start at 7. Add cell 7 = 2. Then 7 - 1 = 6. Add cell 6 = 10. Then 6 - 2 = 4. Add cell 4 = 16. Then 4 - 4 = 0, so stop. The total is 2 + 10 + 16 = 28.

Range sum of positions 2 to 7, before and after. The range is prefix(7) - prefix(1). Before the update: prefix(7) = 2 + 10 + 11 = 23 and prefix(1) = 3, so the answer is 20. After the update: prefix(7) = 28 and prefix(1) is still 3, so the answer is 25. Position 3 is inside the range, so the answer grows by exactly 5.

Edge cases and pitfalls

  • Position 0 in a Fenwick tree. lowbit(0) is 0, so add(0, x) never moves forward and loops forever. Use positions 1 to n, or shift 0-based input by one.
  • Empty prefix. prefix(0) is 0 and the loop does not run. That is why range_sum(1, r) works with prefix(l - 1) = prefix(0).
  • Negative values and deltas. Sums handle them fine. Prefix sums are not monotonic any more, so do not use "walk down while the sum is below X" unless all values are non-negative.
  • Overflow. Many additions can pass the range of a 32-bit integer. Use 64-bit integers, as the sample code does.
  • Update means delta. A Fenwick update adds a difference. To set a position to a new value, add new - old, so you need the old value stored somewhere.
  • Size not a power of two. Both trees work for any n. The Fenwick update stops when the index passes n. The bottom-up segment tree works for any n with 2n cells, though the shape of the tree is uneven. The recursive version needs up to 4n cells.
  • Off-by-one ranges. Decide once whether your range is inclusive or half-open, and write it in the function name or a comment.
  • Lazy tags. Forgetting to push down before reading a child gives stale answers that look almost right.
  • One position or one value. A tree of size 1 is fine: the segment tree has just the leaf at cell 1, and the Fenwick tree has one cell.

Fenwick and segment tree time complexity

OperationPrefix arrayPlain arrayFenwick treeSegment tree
BuildO(n)O(1)O(n) with the linear buildO(n)
Point updateO(n)O(1)O(log n)O(log n)
Range sumO(1)O(n)O(log n)O(log n)
Range min or maxNot possibleO(n)Not possibleO(log n)
Range update (add to a range)O(n)O(n)O(log n) with two treesO(log n) with lazy propagation
SpaceO(n)O(n)O(n)O(n), about 2n to 4n cells

n is the number of values.

Build. Adding the n values one at a time with add costs O(n log n), which is what the sample code does. The linear build is a small change: copy the values into the cells, then for each i from 1 to n, add cell i into its parent cell i + lowbit(i) if that cell exists. Each cell is touched once, so it is O(n). The simulation uses the linear build. The segment tree is linear too, because each internal node is computed once from its two children.

Range update with a Fenwick tree. Store the differences between neighbours in one Fenwick tree. Adding v to positions l to r changes only two differences: add v at l and subtract v at r + 1. A range sum then needs a second Fenwick tree that tracks the differences weighted by position, which is why the table says "two trees". A point value is the prefix sum of the differences.

Neither tree beats a prefix array when nothing changes, and neither beats a plain array when you only change values and never query ranges.

Fenwick and segment trees vs other structures

JobFenwick treeSegment treePrefix sumsSparse tableSquare-root blocks
Range sum, values changeO(log n), tiny codeO(log n)O(n) per changeNot suitedO(√n)
Range sum, values never changeO(log n)O(log n)O(1)O(1)O(1)
Range min or max, values changeNot possibleO(log n)Not possibleRebuild neededO(√n)
Range min or max, values never changeNot possibleO(log n)Not possibleO(1)O(√n)
Range update with lazy valuesAwkwardYesNoNoPossible
Code lengthAbout 15 linesAbout 30 linesAbout 5 linesAbout 15 linesAbout 20 lines

n is the array length. The Fenwick tree wins on sums that change, because it is short and fast. The segment tree wins whenever the operation is not a sum, or ranges themselves change.

How to explain Fenwick and segment trees in an interview

  • Start from the trade-off: a prefix array has fast queries and slow updates, a plain array the reverse. "Both trees make both operations O(log n)."
  • For a Fenwick tree, say what a cell means ("the sum of the last lowbit(i) positions ending at i") and why updates jump forward by lowbit and queries jump backward by it. That is the whole trick.
  • For a segment tree, say "each node is the combination of its two children; a range is split into at most 2 log n whole segments".
  • Name the limits: a sum Fenwick tree needs an operation you can undo (such as sum), a segment tree handles any combine operation, and offline problems may be easier with sorting and a Fenwick tree.

Where you meet Fenwick and segment trees in real systems

The idea of "partial results at different sizes" is common, even where the structure is not called a Fenwick or segment tree. The examples below are illustrative scenarios, not descriptions of any one company's system. Three are drawn out, the first with code you can run, then more examples.

Example 1: Live counters over time buckets

A dashboard shows "orders in the last hour between 10:15 and 10:45" while orders keep arriving. Each minute is one position. A new order adds one to its minute (a point update), and a dashboard query sums a range of minutes. A Fenwick tree does both in O(log n), with one small array. Open the example below to see the picture and the code.

Code: a Fenwick tree with point updates and range sumsTime O(log n)Memory O(n)
Position12345678Covers11-231-455-671-8
Cell 4 holds the sum of positions 1 to 4, cell 6 the sum of positions 5 to 6, and cell 8 the sum of all eight. The sum of positions 1 to 7 is cell 7 + cell 6 + cell 4.
# Fenwick tree (binary indexed tree) for point updates and range sums. Positions are 1 to n.
# Time: O(log n) per update and per prefix sum, O(n log n) to build by adding values one by one.
# Memory: O(n). Only works for operations you can undo, such as sums (not minimum or maximum).
class Fenwick:
    def __init__(self, n):
        self.t = [0] * (n + 1)          # cell 0 is unused

    def add(self, i, delta):            # add delta to position i
        while i < len(self.t):
            self.t[i] += delta
            i += i & -i                 # jump to the next cell that covers position i

    def prefix(self, i):                # sum of positions 1..i
        s = 0
        while i > 0:
            s += self.t[i]
            i -= i & -i                 # remove the lowest set bit
        return s

    def range_sum(self, l, r):          # sum of positions l..r
        return self.prefix(r) - self.prefix(l - 1)

values = [3, 2, 5, 1, 4, 6, 2, 8]
fw = Fenwick(len(values))
for pos, v in enumerate(values, start=1):
    fw.add(pos, v)
print("sum(2,7) before:", fw.range_sum(2, 7))
fw.add(3, 5)                            # add 5 to position 3
print("sum(2,7) after:", fw.range_sum(2, 7))

Each version builds a Fenwick tree from eight values, asks for the sum of positions 2 to 7, adds 5 to position 3, and asks again. Every version was compiled and run, and printed 20 before the update and 25 after it.

Example 2: Range queries with a segment tree

Suppose a monitoring system stores the response time of each request in a time slot and asks "what was the slowest response between slot 100 and slot 900?" while new data keeps arriving. That is a range maximum with updates. A sum Fenwick tree cannot answer it, but a segment tree storing the maximum in every node can, in O(log n).

858 35 68
Each parent holds the larger value of its two children, so the root is the maximum of the whole array. A range query combines a few whole segments instead of looking at every value.

Example 3: Counting inversions with a Fenwick tree

An inversion is a pair of positions where a larger number comes before a smaller one. It measures how unsorted an array is, and it is used in ranking comparisons. Process the array left to right, and for each value ask the Fenwick tree "how many already-seen values are larger?", then add this value. That is O(n log n) for the whole array, against O(n²) for checking every pair.

Take next valueleft to rightQuery the treehow many are largerAdd to the totalinversions so farUpdate the treecount this value
For each value, a Fenwick tree of counts says how many earlier values are larger. Those pairs are the inversions that end at this value. Then the value is added to the tree.

More real-world scenarios

These are illustrative uses of the idea. Real systems often combine it with other techniques, and the details differ.

4. Leaderboards and rank queries

"What is my rank among 10 million players?" is a prefix count over score buckets. A Fenwick tree over score buckets can give the rank in O(log n) while scores change.

5. Databases and analytics

Analytics systems answer sums and counts over time ranges. Some time-bucketed tree structures and indexes use a similar idea of storing results for ranges of different sizes.

6. Games and simulations

A game that asks "how many enemies are in this part of the map?" after every move could keep counts in a tree over map cells, so each move updates a few nodes.

7. Computational geometry

Sweep-line algorithms for rectangle overlap or skyline problems commonly use a segment tree to add and remove intervals and ask for the covered length.

8. Text processing

Counting distinct values in a range, or finding the longest increasing subsequence in O(n log n), uses a segment tree or Fenwick tree over values.

9. Finance

A system that needs the highest price in the last hour while new trades arrive could keep a segment tree for range maximum, or a monotonic queue when the window only slides.

10. Rate limiting and metrics

Counting events in sliding time windows across many buckets can be done with a Fenwick tree over time buckets, which makes both "add an event" and "count between two times" fast.

11. Competitive programming and interviews

Problems about "update a position and query a range" appear often. Knowing which of the two trees fits is often the whole solution.

Language standard libraries

Most standard libraries do not ship either tree. They are short enough that people write them when needed, and several ecosystems have packages.

LanguageBuilt in?What to useNotes
JavaNoWrite itAbout 15 lines for a Fenwick tree. Guava and Apache Commons do not provide one.
C++NoWrite itIn competitive programming everyone has a template. std::partial_sum builds prefix sums only.
C#NoWrite itSame as Java.
RustNoWrite it, or search crates.ioSmall enough that many projects write their own.
PythonNoWrite it, or use NumPy cumsum for static dataitertools.accumulate builds prefix sums.
GoNoWrite itSame as Java.
JavaScriptNoWrite itUse typed arrays (Float64Array) for speed.
KotlinNoWrite itSame as Java.

The takeaway from the table: you will write these yourself. If the data does not change, use the standard prefix-sum helper instead (accumulate, partial_sum or cumsum).

The takeaway

Whenever a system must answer range questions on data that keeps changing, look for a Fenwick tree (sums) or a segment tree (minimum, maximum and everything else). When the data never changes, it usually uses prefix sums or a sparse table instead.

Interview questions

Try answering out loud before you reveal hints. Interviewers care about how you reason, not just the final answer.

  1. 1.

    Design a structure that supports update(i, val) and sumRange(l, r) on an array, with many of each.

    medium
  2. 2.

    For each element, count how many elements to its right are smaller.

    hard
  3. 3.

    What is lazy propagation in a segment tree, and when do you need it?

    hard
  4. 4.

    When would you choose a Fenwick tree over a segment tree, and when not?

    medium

Finished this lesson?

Progress is saved on this device. Create a free account to keep it everywhere.

Topics:Fenwick treeBinary indexed treeSegment treeRange queriesPrefix sumsTrees

↑ Back to top

Next lesson