Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Sparse Table Implementation for Range Queries and Binary Lifting

Notes 2

Sparse Table (ST) is a data structure for answering range queries on static arrays. It differs from standard dynamic programming approaches by storing information only for intervals with lengths that are powers of two.

Standard interval DP might define a state dp[l][r] representing data for the interval (l, r). In contrast, the ST table is defined as ST[l][p], representing the data for the interval starting at index l with length 2^p (spanning [l, l + 2^p - 1]). The 'S' stands for sparse, indicating it stores a subset of all possible intervals.

Application in Jump Distance Problems

A classic use case involves an array of n points where each point i can jump forward a distance jump[i]. A monotonicity condition must hold: if i < j, then jump[i] <= jump[j]. This implies no interval defined by a jump completely contains another, allowing the use of the Sparse Table. The goal is to compute the minimum number of jumps between any two points (l, r).

The recurrence relation for building the table is: ST[i][j] = ST[ ST[i][j-1] ][j-1]

After constructing the table, query are processed by binary lifting: start from position l and greedily apply the largest possible jump 2^step that does not exceed the target r. Step length decreases exponentially to approach the destination.

const int MAX_N = 100000;
const int MAX_LOG = 17;
int jumpDist[MAX_N];
int sparseTable[MAX_N][MAX_LOG];
int n; // Number of points
int maxLog;

void buildSparseTable() {
    maxLog = log2(n) + 1;
    for (int i = 0; i < n; ++i) {
        sparseTable[i][0] = i + jumpDist[i];
    }
    for (int j = 1; j <= maxLog; ++j) {
        for (int i = 0; i < n; ++i) {
            int nextPos = sparseTable[i][j-1];
            if (nextPos < n) {
                sparseTable[i][j] = sparseTable[nextPos][j-1];
            } else {
                sparseTable[i][j] = n; // Out of bounds
            }
        }
    }
}

int minJumps(int start, int end) {
    int currentPos = start;
    int jumpCount = 0;
    if (start >= end) return 0;
    for (int k = maxLog; k >= 0; --k) {
        int nextReach = sparseTable[currentPos][k];
        if (nextReach < end) {
            currentPos = nextReach;
            jumpCount += (1 << k);
        }
    }
    // One final jump is needed to reach or pass 'end'
    return jumpCount + 1;
}

Range Queries for Idempotent Functions

The Sparse Table excels at answering range queries for idempotent or overlap-friendly functions. These are opeartions where the answer for an interval can be derived from the enswers of two overlapping subintervals without loss of information. Examples include maximum, minimum, greatest common divisor (GCD), bitwise AND, and bitwise OR.

For example, to query the maximum value in a range [l, r]:

int arr[MAX_N];
int stMax[MAX_N][MAX_LOG];

void buildMaxTable() {
    for (int i = 0; i < n; ++i) {
        stMax[i][0] = arr[i];
    }
    int logVal = log2(n) + 1;
    for (int j = 1; j <= logVal; ++j) {
        for (int i = 0; i + (1 << j) <= n; ++i) {
            int halfStep = 1 << (j-1);
            stMax[i][j] = std::max(stMax[i][j-1], stMax[i + halfStep][j-1]);
        }
    }
}

int queryMax(int left, int right) {
    int intervalLen = right - left + 1;
    int k = log2(intervalLen);
    return std::max(stMax[left][k], stMax[right - (1 << k) + 1][k]);
}

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.