---
# System prepended metadata

title: Fenwick & Segment Trees - Templates + Applications

---

# Fenwick & Segment Trees - Templates + Applications


## Why These Structures Are Awesome

* Let you go from $O(n^2)$ brute → $O(n \log n)$ (this is the core win)
* Handle **“compare current with all before it”** type problems
* Reusable templates: just swap what you store (counts, sums, max, gcd, etc)
* Scale comfortably to $n \approx 10^5$–$2 \times 10^5$

But they’re **not always needed**.

If the problem is just static prefix sums (like subarray sum existence), a simple prefix array is $O(1)$ per query and way simpler.

Fenwick/Segtree is only worth it if you need *updates + queries* or dynamic sweep-style logic.

---

## What To Keep In Mind

* **Constraints**:

  * $n \approx 10^5$: $O(n \log n)$ is fine
  * $n \approx 10^6+$: log factors start to hurt → maybe you need a math identity, greedy, or offline trick instead of a Fenwick/Segtree
* **Coordinate Compression**:

  * If values are large (like up to $10^9$), compress into $[1..n]$ before storing in Fenwick/Segtree
* **Memory**:

  * Textbook Segment Tree uses about $4n$
  * Fenwick Tree uses $n$
  * Iterative/compact Segment Tree can be closer to $2n$
  * Disclaimer: Segment Tree will always be heavier than Fenwick

---

## When + Where To Use

**Longest Increasing Subsequence (LIS)**

* Solve in $O(n \log n)$ with a Segtree/Fenwick
* State:

  $$
  dp[i] = 1 + \max_{\;a[j] < a[i]} dp[j]
  $$
* Query for max over $[1, a[i]-1]$, then update at $a[i]$

**Inversion Counting**

* Classic Fenwick application
* Count pairs $(i, j)$ with $i < j$ and $a[i] > a[j]$
* Store **counts** in Fenwick

**Weighted Inversion / Difference Problems**

* General class of problems where contribution depends on both the **count** and the **sum** of earlier elements
* Example: for each $a[i]$, add/subtract differences against all previous elements
* Solution: maintain 2 Fenwicks → one for counts, one for sums

**Manhattan Distance Problems (special cases)**

* expand $|x_i - x_j| + |y_i - y_j|$ into linear terms involving counts + sums
* sweep one axis, store the other in Fenwicks
* only shows up in certain geometry/distance problems, not every distance task

**Line Sweep**

* Process events in sorted order (by coordinate or time)
* Maintain “active set” with Fenwick/Segtree
* Shows up in rectangle union, closest pairs, scheduling, etc

---

## Disclaimer

These are **general templates**.

You always tweak what you store (counts, sums, max, gcd, etc) to match the problem.

Don’t overkill, if it’s just prefix sums & the constraints are big enough, use a plain array.

---

## Fenwick Tree (BIT)

```cpp
struct Fenwick {
    int n;
    vector<long long> bit;
    Fenwick(int n) : n(n), bit(n+1,0) {}

    void add(int i, long long x) {
        for (; i <= n; i += i & -i) bit[i] += x;
    }
    long long sum(int i) {
        long long res = 0;
        for (; i > 0; i -= i & -i) res += bit[i];
        return res;
    }
    long long rangeSum(int l, int r) {
        return sum(r) - sum(l-1);
    }
};
```

**Notes:**

* Fenwick = **point update + prefix/range query**.
* Always use `long long` for sums — `n * max(a[i])` can exceed `2e9`.
* If you only store counts (`+1` each time), `int` would be fine, but `ll` is safer universally.

---

## Segment Tree

```cpp
class SegmentTree {
private:
  int n;
  vector<int> tree;

public:
  SegmentTree(int sz) {
    n = 1;
    while (n < sz) n <<= 1;
    tree.assign(2 * n, 0); // iterative style (~2n space)
  }

  void update(int i, int val) {
    i += n;
    tree[i] = max(tree[i], val);
    while (i > 1) {
      i >>= 1;
      tree[i] = max(tree[i << 1], tree[i << 1 | 1]);
    }
  }

  int query(int l, int r) {
    l += n, r += n;
    int res = 0;
    while (l <= r) {
      if (l & 1) res = max(res, tree[l++]);
      if (!(r & 1)) res = max(res, tree[r--]);
      l >>= 1, r >>= 1;
    }
    return res;
  }
};
```
**Notes:**

* This template is tuned for **max queries** (like LIS DP).
* For **sum segment tree**, change the merge op (`+`) and the type to `long long`.
* Point update here is **assign/merge at one index**; range queries aggregate from leaves up.

---


## Templated Segment Tree
```cpp

```

## Example: Weighted Inversion Problem

**Problem (generalized):**

For each element $a[i]$, compute

$$
\text{counter}[i] = 
\sum_{j<i,\;a[j]<a[i]} (a[i] - a[j]) 
\;-\;
\sum_{j<i,\;a[j]>a[i]} (a[j] - a[i])
$$


In other words, for each element `a[i]`, look back at all earlier elements `a[j]`:

* If `a[j] < a[i]`, add the gap `(a[i] - a[j])`.
* If `a[j] > a[i]`, subtract the gap `(a[j] - a[i])`.

So `counter[i]` measures **how much bigger `a[i]` is than the smaller numbers before it, `a[j]`, minus how much smaller it is than the bigger numbers before it.**.

Brute force is $O(n^2)$, which dies at $n = 10^5$.

**Observation:**
This is basically inversion counting with weights:

* normal inversion = just counts
* here = counts + sums

We use two Fenwick Wrees
* One to maintain count of numbers seen so far
* One to maintain sum of numbers seen so far

### Coordinate Compression + Ranking

Fenwick trees only support **prefix queries** (sums over `[1..k]`).

To turn “smaller than `a[i]`” into a prefix query, we:

1. **Compress values**: map each unique value to a rank (1 = smallest, m = largest).

   * Example: arr = `[3,1,4]` → ranks `{1→1, 3→2, 4→3}`.

2. Then:

   * `cnt.sum(idx-1)` = # of elements with rank ≤ `idx-1` = **all elements smaller than `a[i]`**.
   * `sum.sum(idx-1)` = sum of all elements with rank ≤ `idx-1` = **sum of smaller values**.
   * `cnt.sum(m) - cnt.sum(idx)` = # greater.
   * `sum.sum(m) - sum.sum(idx)` = sum of greater values.

So the whole “smaller/greater” logic reduces to simple prefix sums thanks to ranking.

---

### Formula

At each index $i$:

$$
\text{counter}[i] =
\big(a[i] \cdot \text{cntSmaller} - \text{sumSmaller}\big)
+
\big(\text{sumGreater} - a[i] \cdot \text{cntGreater}\big)
$$

Where:

* `cntSmaller = cnt.sum(idx-1)`
* `sumSmaller = sum.sum(idx-1)`
* `cntGreater = cnt.sum(m) - cnt.sum(idx)`
* `sumGreater = sum.sum(m) - sum.sum(idx)`

**Code:**

```cpp
vector<long long> solve(vector<int>& arr) {
    int n = arr.size();

    // coordinate compression
    vector<int> vals = arr;
    sort(vals.begin(), vals.end());
    vals.erase(unique(vals.begin(), vals.end()), vals.end());
    
    auto get = [&](int x) {
        return int(lower_bound(vals.begin(), vals.end(), x) - vals.begin()) + 1;
    };
    int m = vals.size();

    Fenwick cnt(m), sum(m);
    vector<long long> ans(n);

    for (int i = 0; i < n; i++) {
        int idx = get(arr[i]);

        long long cntSmaller = cnt.sum(idx-1);
        long long sumSmaller = sum.sum(idx-1);

        long long cntAll = cnt.sum(m);
        long long sumAll = sum.sum(m);

        long long cntGreater = cntAll - cnt.sum(idx);
        long long sumGreater = sumAll - sum.sum(idx);

        long long res = arr[i]*cntSmaller - sumSmaller;
        
        res += sumGreater - arr[i]*cntGreater;
        ans[i] = res;

        cnt.add(idx, 1);
        sum.add(idx, arr[i]);
    }
    
    long long total = 0;
    
    for (int i = 0; i < n; i++) {
        total += ans[i];
    }
    
    return total;
}
```

---

# Quick Cheat Table

| Problem type                  | What to store in tree          |
| ----------------------------- | ------------------------------ |
| Inversion counting            | Counts only                    |
| LIS (dp style)                | Max DP value                   |
| Weighted inversions/diffs     | Counts + Sums                  |
| Manhattan distance (2D sweep) | Counts + Sums (sweep one axis) |
| Range sum query               | Prefix Sums                    |
| Range min/max/gcd             | Segtree with Merge Op          |

## Recommended problems

* [USACO Guide – Longest Increasing Subsequence](https://usaco.guide/gold/lis)
* [USACO Guide – Point Update Range Sum](https://usaco.guide/gold/PURS)
* [USACO Guide – Range Query Section from Plat](https://usaco.guide/plat/)

