Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Range Sum Queries on Sparse Coordinates using Compression

Tools Apr 19 18

Consider an infinite linear axis where every integer coordinate holds an initial value of zero. The task involves processing $n$ point increment operations followed by anwsering $m$ range sum queries.

Given that coordinates may span $[-10^9, 10^9]$ while $n, m \leq 10^5$, direct array allocation is infeasible. However, only coordinates appearing in operations or query boundaries influence results. This motivates coordinate compression to map the sparse coordinate set to a dense contiguous range $[1, k]$ where $k \leq n + 2m$.

Algorithm Overview

  1. Collection: Gather all positions from updates and all interval endpoints from queries into a single list.
  2. Discretization: Sort the list and remove duplicates, establishing a mapping from original coordinates to ranks $1$ through $k$.
  3. Accumulation: Apply all point increments using the compressed indices.
  4. Prefix Summation: Compute cumulative sums over the compressed domain to answer range queries in constant time.
  5. Query Processing: Map each query's endpoints to their compressed ranks and compute the difference of prefix sums.

Implementation

#include <bits/stdc++.h>
using namespace std;

const int MAX_COORDS = 300010;

struct PointUpdate {
    int coord;
    int delta;
};

struct RangeQuery {
    int left;
    int right;
};

vector<int> compressed;
vector<PointUpdate> updates;
vector<RangeQuery> queries;
int values[MAX_COORDS];
int prefix[MAX_COORDS];

int getIndex(int x) {
    return lower_bound(compressed.begin(), compressed.end(), x) - compressed.begin() + 1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    cin >> n >> m;
    
    for (int i = 0; i < n; ++i) {
        int x, c;
        cin >> x >> c;
        updates.push_back({x, c});
        compressed.push_back(x);
    }
    
    for (int i = 0; i < m; ++i) {
        int l, r;
        cin >> l >> r;
        queries.push_back({l, r});
        compressed.push_back(l);
        compressed.push_back(r);
    }
    
    sort(compressed.begin(), compressed.end());
    compressed.erase(unique(compressed.begin(), compressed.end()), compressed.end());
    
    for (const auto &op : updates) {
        int idx = getIndex(op.coord);
        values[idx] += op.delta;
    }
    
    for (int i = 1; i <= (int)compressed.size(); ++i) {
        prefix[i] = prefix[i - 1] + values[i];
    }
    
    for (const auto &q : queries) {
        int l = getIndex(q.left);
        int r = getIndex(q.right);
        cout << prefix[r] - prefix[l - 1] << '\n';
    }
    
    return 0;
}

The algorithm operates in $O((n+m) \log (n+m))$ time complexity due to sorting, with $O(n+m)$ space complexity. Each query is resolved in $O(1)$ time after preprocessing.

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

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