Segment Tree Implementation for Range Queries and Updates

The segment tree is constructed recursively. Each node tracks its segment boundaries [left, right]. Leaf nodes correspond to individual array elements, while enternal nodes store the sum of their children.


struct SegmentTree {
    int left[MAX_N * 4], right[MAX_N * 4];
    long long value[MAX_N * 4], lazy[MAX_N * 4];

    void build(int l, int r, int idx) {
        left[idx] = l;
        right[idx] = r;
        if (l == r) {
            scanf("%lld", &value[idx]);
            return;
        }
        int mid = (l + r) / 2;
        build(l, mid, idx * 2);
        build(mid + 1, r, idx * 2 + 1);
        value[idx] = value[idx * 2] + value[idx * 2 + 1];
    }
};

Point Update

To update a single element, traverse from the root to the target leaf, modifying values along the path.


void pointUpdate(int idx, int pos, int delta) {
    if (left[idx] == right[idx]) {
        value[idx] += delta;
        return;
    }
    if (lazy[idx]) pushLazy(idx);
    int mid = (left[idx] + right[idx]) / 2;
    if (pos <= mid) pointUpdate(idx * 2, pos, delta);
    else pointUpdate(idx * 2 + 1, pos, delta);
    value[idx] = value[idx * 2] + value[idx * 2 + 1];
}

Point Query

Retrieve a single element by traversing to the corresponding leaf node.


long long pointQuery(int idx, int pos) {
    if (left[idx] == right[idx]) return value[idx];
    if (lazy[idx]) pushLazy(idx);
    int mid = (left[idx] + right[idx]) / 2;
    if (pos <= mid) return pointQuery(idx * 2, pos);
    else return pointQuery(idx * 2 + 1, pos);
}

Range Query

For range queries, combine results from segments that fully or partially overlap with the query range.


long long rangeQuery(int ql, int qr, int idx) {
    if (ql <= left[idx] && right[idx] <= qr) return value[idx];
    if (lazy[idx]) pushLazy(idx);
    int mid = (left[idx] + right[idx]) / 2;
    long long result = 0;
    if (ql <= mid) result += rangeQuery(ql, qr, idx * 2);
    if (qr > mid) result += rangeQuery(ql, qr, idx * 2 + 1);
    return result;
}

Range Update with Lazy Propagation

Lazy propagation defers updates until necessary. When updating a range, mark nodes that fully cover the range and propagate changes later during queries or updates.


void pushLazy(int idx) {
    lazy[idx * 2] += lazy[idx];
    lazy[idx * 2 + 1] += lazy[idx];
    value[idx * 2] += lazy[idx] * (right[idx * 2] - left[idx * 2] + 1);
    value[idx * 2 + 1] += lazy[idx] * (right[idx * 2 + 1] - left[idx * 2 + 1] + 1);
    lazy[idx] = 0;
}

void rangeUpdate(int ql, int qr, int idx, int delta) {
    if (ql <= left[idx] && right[idx] <= qr) {
        value[idx] += delta * (right[idx] - left[idx] + 1);
        lazy[idx] += delta;
        return;
    }
    if (lazy[idx]) pushLazy(idx);
    int mid = (left[idx] + right[idx]) / 2;
    if (ql <= mid) rangeUpdate(ql, qr, idx * 2, delta);
    if (qr > mid) rangeUpdate(ql, qr, idx * 2 + 1, delta);
    value[idx] = value[idx * 2] + value[idx * 2 + 1];
}

Note: Array storage requires 4 times the original data size to accommodate the tree structure. Practice implementing and simulating these operations to gain proficiency.

Tags: segment-tree data-structures range-query lazy-propagation binary-tree

Posted on Thu, 18 Jun 2026 17:26:51 +0000 by hkothari