Fundamentals 7 min read

Why This Design Works and How a Fenwick Tree Simplifies Inversion Counting

The article explains what inversion pairs are, demonstrates a naïve O(n²) counting method, then introduces a smarter right‑to‑left approach using a Fenwick (Binary Indexed) tree with discretization to achieve efficient O(n log n) inversion counting, providing full Python implementations and step‑by‑step examples.

YiSu Grain
YiSu Grain
YiSu Grain
Why This Design Works and How a Fenwick Tree Simplifies Inversion Counting

An inversion pair consists of two elements (a, b) in an array where a appears before b and a > b. For example, in the array [30,10,40,20] the pairs (30,10), (30,20) and (40,20) are inversions.

Naïve O(n²) solution

The straightforward method scans each element and compares it with every element to its right, counting how many smaller elements follow it. Applied to the example array, the algorithm finds three inversion pairs.

def count_inversions_brutal(arr):
    count = 0
    for i in range(len(arr)):
        for j in range(i+1, len(arr)):
            if arr[i] > arr[j]:
                count += 1
    return count

arr = [5, 2, 6, 1]
print(count_inversions_brutal(arr))

More clever right‑to‑left method

Instead of two nested loops, process the array from right to left, keeping a list of elements already seen. For each new element, count how many of the previously seen elements are smaller.

Example walk‑through on [5,2,6,1]:

Start with 1 → seen = [1]; smaller count = 0.

Next 6 → seen = [1,6]; smaller count = 1 (the 1).

Next 2 → seen = [1,6,2]; smaller count = 1 (the 1).

Next 5 → seen = [1,6,2,5]; smaller count = 2 (1 and 2).

def count_inversions_simple(arr):
    n = len(arr)
    count = 0
    seen = []
    for i in range(n-1, -1, -1):
        current = arr[i]
        smaller_count = sum(1 for x in seen if x < current)
        count += smaller_count
        seen.append(current)
    return count

arr = [5, 2, 6, 1]
print(count_inversions_simple(arr))

While easier to understand than the brute‑force approach, this method still requires O(n²) time for large inputs because the sum scan over seen is linear.

Fenwick (Binary Indexed) Tree optimization

A Fenwick tree acts as a compact counter that supports prefix‑sum queries and point updates in O(log n) time. By discretizing the array values to a small integer range, the tree can efficiently track how many smaller elements have been seen.

Discretization example for [5,2,6,1]: after sorting and removing duplicates we obtain [1,2,5,6] with ranks 1‑4.

data:   '1'  '2'  '5'  '6'
position: 1   2   3   4

Processing the original array from right to left:

1 → no smaller elements; update rank 1.

6 → query prefix sum up to rank‑1 (3) → 1 smaller element; update rank 4.

2 → query up to rank‑1 (1) → 1 smaller element; update rank 2.

5 → query up to rank‑1 (2) → 2 smaller elements; update rank 3.

The tree maintains counts at each position, allowing each query and update to run in logarithmic time.

def count_inversions(arr):
    sorted_arr = sorted(set(arr))
    rank = {v: i+1 for i, v in enumerate(sorted_arr)}
    n = len(arr)
    bit = [0] * (n + 1)
    count = 0
    for i in range(n-1, -1, -1):
        curr_rank = rank[arr[i]]
        small_count = 0
        idx = curr_rank - 1
        while idx > 0:
            small_count += bit[idx]
            idx -= (idx & -idx)
        count += small_count
        idx = curr_rank
        while idx <= n:
            bit[idx] += 1
            idx += (idx & -idx)
    return count

arr = [5, 2, 6, 1]
print(count_inversions(arr))

Summary

The example demonstrates how a Fenwick tree combined with discretization and reverse traversal yields an O(n log n) algorithm for counting inversion pairs. The key steps are:

Discretization : map array values to a compact rank range.

Reverse traversal : ensure each query only sees elements that appear to the right of the current element.

Fenwick updates and queries : use the tree to record occurrences and retrieve the count of smaller elements efficiently.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

algorithmPythonBinary Indexed TreeFenwick treeinversion counting
YiSu Grain
Written by

YiSu Grain

A fleeting mayfly in the world, a single grain in the boundless sea.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.