Fenwick Tree

Introduction

A Fenwick tree is a compact data structure with little code that supports point updates and range queries.

What are “point updates” and “range queries”?

Suppose we have the following problem:

Given a sequence aa, perform the following two operations:

  • Given x,yx, y, increase a[x]a[x] by yy.
  • Given l,rl, r, find the sum of a[l…r]a[l \ldots r].

The first operation is a “point update”, and the second is a “range query”.

Similarly, there are “range updates” and “point queries”. Here is one example of each:

  • Range update: given l,r,xl, r, x, increase every number in a[l…r]a[l \ldots r] by xx;
  • Point query: given xx, find the value of a[x]a[x].

Notice that range problems are generally strictly stronger than point problems, because an operation on a point is equivalent to an operation on an interval of length 11.

A standard Fenwick tree maintains information and operations that satisfy associativity and support differences, such as addition (sums), multiplication (products), and XOR.

  • Associativity: (x∘y)∘z=x∘(y∘z)(x \circ y) \circ z = x \circ (y \circ z), where ∘\circ is a binary operator.
  • Supporting differences: an operation with an inverse, meaning that given x∘yx \circ y and xx, we can find yy.

It is important to note:

  • For multiplication modulo a modulus to support differences, every number must have an inverse (which is always true when the modulus is prime);
  • Information such as gcd⁡\gcd and max⁡\max does not support differences, so it cannot be handled by a standard Fenwick tree. However:

In fact, the problems a Fenwick tree can solve form a subset of those solvable by a segment tree: everything a Fenwick tree can do, a segment tree can certainly do; everything a segment tree can do, a Fenwick tree cannot necessarily do. However, Fenwick-tree code is much shorter than segment-tree code, and its constant factors are smaller, so it is still worth studying.

Sometimes, with the help of a difference array and auxiliary arrays, a Fenwick tree can also solve the stronger problems of range additions with point-value queries and range additions with range-sum queries.

Fenwick tree

First intuition

Let us start with an example: how do we find the prefix sum of a[1…7]a[1 \ldots 7]?

One way is to compute a1+a2+a3+a4+a5+a6+a7a_1 + a_2 + a_3 + a_4 + a_5 + a_6 + a_7, which requires summing 77 numbers.

But what if we know three numbers AA, BB, and CC, where A=a[1…4]A = a[1 \ldots 4] is a sum, B=a[5…6]B = a[5 \ldots 6] is a total, and C=a[7…7]C = a[7 \ldots 7] is a total (which is just a[7]a[7] itself)? How would you calculate it? You would certainly answer: A+B+CA + B + C, requiring only the sum of 33 numbers.

This is why a Fenwick tree can answer queries quickly: we can always split a prefix [1,n][1, n] into no more than log⁡n\boldsymbol{\log n} intervals, so that the information of these log⁡n\log n intervals is known.

Thus, we only need to combine the information from these log⁡n\log n intervals to obtain the answer. Compared with directly combining nn pieces of information, this is a major improvement in efficiency.

It is easy to see that the information must satisfy associativity; otherwise, it could not be combined as above.

The figure below illustrates how a Fenwick tree works:

Figure: fenwick

The eight blocks at the bottom represent the original data array aa. The uneven blocks above (which form the same eight-position array as the top row) represent the parent array of aa, namely cc.

The cc array stores the sum of a certain interval of the original array aa; in other words, the information for these intervals is known, and our goal is to decompose a queried prefix into these small intervals.

For example, as the figure shows:

  • c2c_2 governs a[1…2]a[1 \ldots 2];
  • c4c_4 governs a[1…4]a[1 \ldots 4];
  • c6c_6 governs a[5…6]a[5 \ldots 6];
  • c8c_8 governs a[1…8]a[1 \ldots 8];
  • Every remaining c[x]c[x] governs a[x]a[x] itself (which can be viewed as the interval a[x…x]a[x \ldots x] of length 11).

It is easy to see that c[x]c[x] always governs an interval whose right endpoint is xx. We will ignore the left endpoint for now and first build intuition for how a Fenwick tree performs a query.

Example: compute the sum of a[1…7]a[1 \ldots 7].

Process: start at c7c_{7} and jump backward. We find that c7c_{7} governs only the element a7a_{7}; then inspect c6c_{6} and find that c6c_{6} governs a[5…6]a[5 \ldots 6]; then jump to c4c_{4} and find that c4c_{4} governs the elements a[1…4]a[1 \ldots 4]; finally, we try to jump to c0c_0, but c0c_0 does not actually exist, so we stop.

The cc values we found are c7,c6,c4c_7, c_6, c_4. These are exactly the three small intervals into which a[1…7]a[1 \ldots 7] was decomposed, so combining them gives c7+c6+c4c_7 + c_6 + c_4.

Example: compute the sum of a[4…7]a[4 \ldots 7].

Again, we start at c7c_7, jump to c6c_6, and then jump to c4c_4. We now find that it governs the sum of a[1…4]a[1 \ldots 4], but we do not want the a[1…3]a[1 \ldots 3] part. What should we do? Simply subtract the sum of a[1…3]a[1 \ldots 3].

We can instead begin by converting the query for the sum of a[4…7]a[4 \ldots 7] into a query for the sum of a[1…7]a[1 \ldots 7] and a query for the sum of a[1…3]a[1 \ldots 3], then subtract the two results.

Figure: fenwick query

Governed intervals

This raises the question: how far to the left does c[x](x≥1)c[x](x \ge 1) extend? In other words, what is the interval length?

In a Fenwick tree, the interval governed by c[x]c[x] is defined to have length 2k2^{k}, where:

  • If the least significant bit is bit 00, then kk is exactly the bit position in the binary representation of xx corresponding to the lowest 1;
  • 2k2^k (the length of the interval governed by c[x]c[x]) is exactly the number formed by the binary representation of xx's lowest 1 and all subsequent 0 bits.

For example, which interval does c88c_{88} govern?

Because 88(10)=01011000(2)88_{(10)}=01011000_{(2)}, the lowest 1 and the subsequent 0 bits form the binary number 1000, namely 88, so c88c_{88} governs 88 elements of the aa array.

Therefore, c88c_{88} represents the interval information for a[81…88]a[81 \ldots 88].

Let the number formed by the lowest bits of the binary representation of xx—the 1 bit and all subsequent 0 bits—be lowbit⁡(x)\operatorname{lowbit}(x). Then the interval governed by c[x]c[x] is [x−lowbit⁡(x)+1,x][x-\operatorname{lowbit}(x)+1, x].

Note

lowbit⁡\operatorname{lowbit} is not the bit position of the lowest 1, namely kk; it is formed by that 1 and all subsequent 0 bits, namely 2k2^k.

How do we compute lowbit? From bitwise operations, we obtain lowbit(x) = x & -x.

The principle behind lowbit

Taking the complement of every bit in the binary representation of x and then adding 1 gives the binary encoding of -x. For example, the binary encoding of 66 is 110; complementing every bit gives 001, and adding 1 gives 010.

Suppose the original binary encoding of x is (...)10...00. Complementing every bit gives [...]01...11; adding 1 gives [...]10...00, which is the binary encoding of -x. Here, x has first binary bit 1; this is the lowest occurrence in x, namely 1.

Every bit represented by the ellipses in (...) and [...] is complementary, so x & -x = (...)10...00 & [...]10...00 = 10...00, whose result is lowbit.

Implementation

C++

int lowbit(int x) {
  // The number formed by the lowest 1 bit of x and all subsequent 0 bits in binary.
  // lowbit(0b01011000) == 0b00001000
  //          ~~~~^~~~
  // lowbit(0b01110010) == 0b00000010
  //          ~~~~~~^~
  return x & -x;
}

Python

def lowbit(x):
    """
    The value formed by the lowest set bit of x and all trailing zeros in its binary representation.
    lowbit(0b01011000) == 0b00001000
            ~~~~~^~~
    lowbit(0b01110010) == 0b00000010
            ~~~~~~~^~
    """
    return x & -x

Range queries

Next, let us examine the concrete operations on a Fenwick tree, starting with range queries.

Recall the process for querying a[4…7]a[4 \ldots 7]: we converted it into two subqueries, the sum of a[1…7]a[1 \ldots 7] and the sum of a[1…3]a[1 \ldots 3], and then took their difference.

In fact, every range query can be handled this way: the sum of a[l…r]a[l \ldots r] is the sum of a[1…r]a[1 \ldots r] minus the sum of a[1…l−1]a[1 \ldots l - 1], converting a range problem into a prefix problem that is easier to handle.

In contests, converting a range query over l…rl \ldots r into two prefix queries over 1…r1 \ldots r and 1…l−11 \ldots l - 1, then taking their difference, is a very common technique.

How do we perform a prefix query? Recall the process for querying a[1…7]a[1 \ldots 7]:

Jump backward from c7c_{7}: c7c_{7} governs only the element a7a_{7}; then inspect c6c_{6} and find that c6c_{6} governs a[5…6]a[5 \ldots 6]; jump to c4c_{4} and find that c4c_{4} governs the elements a[1…4]a[1 \ldots 4]; then try to jump to c0c_0. But c0c_0 does not actually exist, so we stop.

The cc values we found are c7,c6,c4c_7, c_6, c_4. These are exactly the three small intervals into which a[1…7]a[1 \ldots 7] was decomposed; combining them gives c7+c6+c4c_7 + c_6 + c_4.

Observe that at each step we jump to the position immediately to the left of the current interval's left endpoint, making it the right endpoint of the new interval. This is necessary to decompose the prefix without gaps or overlaps. For example, c6c_6 governs a[5…6]a[5 \ldots 6], so the next jump is to 5−1=45 - 1 = 4, accessing c4c_4.

We can write the process for querying a[1…x]a[1 \ldots x] as follows:

  • Start from c[x]c[x] and jump backward; c[x]c[x] governs a[x−lowbit⁡(x)+1…x]a[x-\operatorname{lowbit}(x)+1 \ldots x].
  • Set x←x−lowbit⁡(x)x \gets x - \operatorname{lowbit}(x). If x=0x = 0, we have reached the end and terminate the loop; otherwise, return to the first step.
  • Combine the cc values reached.

When implementing this, we do not need to collect all the cc values first and combine them afterward; we can combine them while jumping.

For example, if the maintained information is a sum, set the initial ans=0\mathrm{ans} = 0. Each time we reach a c[x]c[x], set ans←ans+c[x]\mathrm{ans} \gets \mathrm{ans} + c[x]; the final ans\mathrm{ans} is the result of combining them all.

Implementation

C++

int getsum(int x) {  // sum of a[1]..a[x]
  int ans = 0;
  while (x > 0) {
    ans = ans + c[x];
    x = x - lowbit(x);
  }
  return ans;
}

Python

def getsum(x):  # sum of a[1]..a[x]
    ans = 0
    while x > 0:
        ans = ans + c[x]
        x = x - lowbit(x)
    return ans

Fenwick-tree properties and its tree structure

Before discussing point updates, let us first explain several basic properties of a Fenwick tree and the origin of its tree structure; this will make point updates easier to understand.

We use the following conventions:

  • l(x)=x−lowbit⁡(x)+1l(x) = x - \operatorname{lowbit}(x) + 1. That is, l(x)l(x) is the left endpoint of the range governed by c[x]c[x].
  • For every positive integer xx, we can write xx in the form s×2k+1+2ks \times 2^{k + 1} + 2^k, where lowbit⁡(x)=2k\operatorname{lowbit}(x) = 2^k.
  • The statement “c[x]c[x] and c[y]c[y] are disjoint” means that the ranges governed by c[x]c[x] and c[y]c[y] do not intersect, namely that [l(x),x][l(x), x] and [l(y),y][l(y), y] are disjoint. The meaning of statements such as “c[x]c[x] is contained in c[y]c[y]” is analogous.

Property 1\boldsymbol{1}: for x≤y\boldsymbol{x \le y}, either c[x]\boldsymbol{c[x]} and c[y]\boldsymbol{c[y]} are disjoint, or c[x]\boldsymbol{c[x]} is contained in c[y]\boldsymbol{c[y]}.

Proof

Proof: suppose c[x]c[x] and c[y]c[y] intersect, meaning that [l(x),x][l(x), x] and [l(y),y][l(y), y] intersect. Then l(y)≤x≤yl(y) \le x \le y.

Write yy as s×2k+1+2ks \times 2^{k +1} + 2^k, so l(y)=s×2k+1+1l(y) = s \times 2^{k + 1} + 1. Therefore, xx can be written as s×2k+1+bs \times 2^{k +1} + b, where 1≤b≤2k1 \le b \le 2^k.

It is easy to see that lowbit⁡(x)=lowbit⁡(b)\operatorname{lowbit}(x) = \operatorname{lowbit}(b). Also, b−lowbit⁡(b)≥0b - \operatorname{lowbit}(b) \ge 0,

so l(x)=x−lowbit⁡(x)+1=s×2k+1+b−lowbit⁡(b)+1≥s×2k+1+1=l(y)l(x) = x - \operatorname{lowbit}(x) + 1 = s \times 2^{k +1} + b - \operatorname{lowbit}(b) +1 \ge s \times 2^{k +1} + 1 = l(y), that is, l(y)≤l(x)≤x≤yl(y) \le l(x) \le x \le y.

Therefore, if c[x]c[x] and c[y]c[y] intersect, the range governed by c[x]c[x] must be completely contained in c[y]c[y].

Property 2\boldsymbol{2}: c[x]\boldsymbol{c[x]} is strictly contained in c[x+lowbit⁡(x)]\boldsymbol{c[x + \operatorname{lowbit}(x)]}.

Proof

Proof: let y=x+lowbit⁡(x)y = x + \operatorname{lowbit}(x) and x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k. Then y=(s+1)×2k+1y = (s + 1) \times 2^{k +1} and l(x)=s×2k+1+1l(x) = s \times 2^{k + 1} + 1.

It is easy to see that lowbit⁡(y)≥2k+1\operatorname{lowbit}(y) \ge 2^{k + 1}, so l(y)=(s+1)×2k+1−lowbit⁡(y)+1≤s×2k+1+1=l(x)l(y) = (s + 1) \times 2^{k + 1} - \operatorname{lowbit}(y) + 1 \le s \times 2^{k +1} + 1= l(x), that is, l(y)≤l(x)≤x<yl(y) \le l(x) \le x < y.

Therefore, c[x]c[x] is strictly contained in c[x+lowbit⁡(x)]c[x + \operatorname{lowbit}(x)].

Property 33: for any x<y<x+lowbit⁡(x)\boldsymbol{x < y < x + \operatorname{lowbit}(x)}, c[x]\boldsymbol{c[x]} and c[y]\boldsymbol{c[y]} are disjoint.

Proof

Proof: let x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k. Then y=x+b=s×2k+1+2k+by = x + b = s \times 2^{k + 1} + 2^k + b, where 1≤b<2k1 \le b < 2^k.

It is easy to see that lowbit⁡(y)=lowbit⁡(b)\operatorname{lowbit}(y) = \operatorname{lowbit}(b). Also, b−lowbit⁡(b)≥0b - \operatorname{lowbit}(b) \ge 0,

Therefore, l(y)=y−lowbit⁡(y)+1=x+b−lowbit⁡(b)+1>xl(y) = y - \operatorname{lowbit}(y) + 1 = x + b - \operatorname{lowbit}(b) + 1 > x, that is, l(x)≤x<l(y)≤yl(x) \le x < l(y) \le y.

Therefore, c[x]c[x] and c[y]c[y] are disjoint.

With these three properties in place, we can now examine the tree structure of a Fenwick tree (ignore the edges from aa to cc).

Figure: fenwick

In fact, the tree structure of a Fenwick tree is the graph formed by connecting xx to x+lowbit⁡(x)x + \operatorname{lowbit}(x), where x+lowbit⁡(x)x + \operatorname{lowbit}(x) is the parent of xx.

When considering this tree structure, we ignore the size of the Fenwick tree and regard it as an infinite tree for convenience. In an actual implementation, for x≤nx \le n we only use c[x]c[x], where nn is the length of the original array.

This tree naturally has many useful properties. We list several below (let fa[u]fa[u] denote the direct parent of uu):

  • u<fa[u]u < fa[u].
  • uu is greater than every descendant of uu and less than every ancestor of uu.
  • Node uu's lowbit⁡\operatorname{lowbit} is strictly less than fa[u]fa[u]'s lowbit⁡\operatorname{lowbit}.
Proof

Let y=x+lowbit⁡(x)y = x + \operatorname{lowbit}(x) and x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k. Then y=(s+1)×2k+1y = (s + 1) \times 2^{k +1}. It is easy to see that lowbit⁡(y)≥2k+1>lowbit⁡(x)\operatorname{lowbit}(y) \ge 2^{k + 1} > \operatorname{lowbit}(x), as required.

  • The height of node xx is log⁡2lowbit⁡(x)\log_2\operatorname{lowbit}(x), namely the bit position in the binary representation of xx corresponding to 1.
Definition of height

The height of node xx, denoted h(x)h(x), satisfies: if x mod 2=1x \bmod 2 = 1, then h(x)=0h(x) = 0; otherwise, h(x)=max⁡(h(y))+1h(x) = \max(h(y)) + 1, where yy ranges over all children of xx (in this case, xx has at least one child, x−1x - 1).

In other words, a node's height is exactly 11 greater than that of its highest child. If a node has no children, its height is 00.

We introduce height here to make the later complexity analysis easier to explain.

  • c[u]c[u] is strictly contained in c[fa[u]]c[fa[u]] (Property 22).
  • c[u]c[u] is strictly contained in c[v]c[v], where vv is any ancestor of uu (by induction on the preceding property).
  • c[u]c[u] strictly contains c[v]c[v], where vv is any descendant of uu (the preceding property with uu and vv exchanged).
  • For any v′>uv' > u, if v′v' is not an ancestor of uu, then c[u]c[u] and c[v′]c[v'] are disjoint.
Proof

Among uu and the ancestors of uu, there must be a node vv such that v<v′<fa[v]v < v' < fa[v]. By Property 33, c[v′]c[v'] is disjoint from c[v]c[v]; since c[v]c[v] contains c[u]c[u], c[v′]c[v'] is therefore disjoint from c[u]c[u].

  • For any v<uv < u, if vv is not in the subtree of uu, then c[u]c[u] and c[v]c[v] are disjoint (the preceding property with uu and v′v' exchanged).
  • For any v>uv > u, the condition that vv is an ancestor of uu is equivalent to c[u]c[u] being strictly contained in c[v]c[v] (a summary of the preceding properties). This is the core principle behind Fenwick-tree point updates.
  • Let u=s×2k+1+2ku = s \times 2^{k + 1} + 2^k. Then the number of its children is k=log⁡2lowbit⁡(u)k = \log_2\operatorname{lowbit}(u), and their indices are u−2t(0≤t<k)u - 2^t(0 \le t < k).
    • For example, suppose k=3k = 3 and the binary index of uu is ...1000. Then uu has three children, whose binary indices are ...0111, ...0110, and ...0100.
Proof

Starting from a number xx, subtracting 2t2^t flips the bit in the binary representation of xx at position tt, while the lower bits remain unchanged.

Consider uu and one of its children, vv. We have v+lowbit⁡(v)=uv + \operatorname{lowbit}(v) = u, so v=u−2tv = u - 2^t and lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t. Let u=s×2k+1+2ku = s \times 2^{k + 1} + 2^k.

Consider 0≤t<k\boldsymbol{0 \le t < k}. Bits of uu at and below position tt are all 00, so in v=u−2tv = u - 2^t, bit tt becomes 11 while the lower bits remain 00; this satisfies lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t.

Consider t=k\boldsymbol{t = k}. Then v=u−2kv = u - 2^k; in vv, bit kk becomes 00; this does not satisfy lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t.

Consider t>k\boldsymbol{t > k}. Then v=u−2tv = u - 2^t; in vv, bit kk is 11, so lowbit⁡(v)=2k\operatorname{lowbit}(v) = 2^k; this does not satisfy lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t.

  • The ranges governed by all children of uu in cc concatenate exactly to [l(u),u−1][l(u), u - 1].
    • For example, suppose k=3k = 3 and the binary index of uu is ...1000. Then uu has three children, whose binary indices are ...0111, ...0110, and ...0100.
    • c[...0100] represents a[...0001 ~ ...0100].
    • c[...0110] represents a[...0101 ~ ...0110].
    • c[...0111] represents a[...0111 ~ ...0111].
    • It is easy to see that the union of the three ranges above is exactly a[...0001 ~ ...0111], namely [l(u),u−1][l(u), u - 1].
Proof

Every child of uu can be written as u−2t(0≤t<k)u - 2^t(0 \le t < k). It is easy to see that the smaller tt is, the larger u−2tu - 2^t is, so its interval lies farther to the right. Let f(t)=u−2tf(t) = u - 2^t; then f(k−1),f(k−2),…,f(0)f(k - 1), f(k - 2), \ldots, f(0) are the children of uu from left to right.

It is easy to see that lowbit⁡(f(t))=2t\operatorname{lowbit}(f(t)) = 2^t, so l(f(t))=u−2t−2t+1=u−2t+1+1l(f(t)) = u - 2^t - 2^t + 1 = u - 2^{t + 1} + 1.

Consider adjacent children f(t+1)f(t + 1) and f(t)f(t). The right endpoint of the former's governed interval is f(t+1)=u−2t+1f(t + 1) = u - 2^{t + 1}, while the left endpoint of the latter's governed interval is l(f(t))=u−2t+1+1l(f(t)) = u - 2^{t + 1} + 1; they meet exactly.

Consider the leftmost child f(k−1)f(k - 1). Its governed left boundary is l(f(k−1))=u−2k+1l(f(k - 1)) = u - 2^k + 1, exactly l(u)l(u).

Consider the rightmost child f(0)f(0). Its governed right boundary is u−1u - 1.

Therefore, the ranges governed by these children concatenate exactly to [l(u),u−1][l(u), u - 1].

Point updates

Now let us consider how to perform a point update on a[x]a[x].

Our goal is to maintain the cc array quickly and correctly. For efficiency, we only need to traverse and update the entries that govern a[x]a[x], namely the c[y]c[y] values, because the other cc values have obviously not changed.

Every entry governing a[x]a[x], namely c[y]c[y], must contain c[x]c[x] (by Property 11), so yy is an ancestor of xx in the Fenwick-tree structure. Therefore, we start at xx and repeatedly jump to the parent until we pass the length of the original array.

Let nn denote the size of aa. The process for a point update on a[x]a[x] is easy to write:

  • Initially set x′=xx' = x.
  • Update c[x′]c[x'].
  • Set x′←x′+lowbit⁡(x′)x' \gets x' + \operatorname{lowbit}(x'). If x′>nx' > n, we have reached the end and terminate the loop; otherwise, return to the second step.

The interval information and the type of point update together determine how to update c[x′]c[x']. Here are several examples:

  • If c[x′]c[x'] stores a range sum and the update on a[x]a[x] adds pp, then add to every corresponding c[x′]c[x'] the amount pp.
  • If c[x′]c[x'] stores a range product and the update on a[x]a[x] multiplies by pp, then multiply every corresponding c[x′]c[x'] by pp.

However, the flexibility of point updates means that the update operation and the maintained information need not use the same operation. For example, if c[x′]c[x'] stores a range sum and the update assigns a[x]a[x] the value pp, we can convert it into adding to a[x]a[x] the amount p−a[x]p - a[x]. If instead it multiplies a[x]a[x] by pp, we can convert it into adding to a[x]a[x] the amount a[x]×p−a[x]a[x] \times p - a[x].

Here is an implementation that maintains range sums with point additions.

Implementation

C++

void add(int x, int k) {
  while (x <= n) {  // do not go out of bounds
    c[x] = c[x] + k;
    x = x + lowbit(x);
  }
}

Python

def add(x, k):
    while x <= n:  # do not go out of bounds
        c[x] = c[x] + k
        x = x + lowbit(x)

Building the tree

That is, build the Fenwick tree from the original sequence given at the beginning (precomputing all of cc).

The straightforward method is to convert this into nn point updates, with time complexity Θ(nlog⁡n)\Theta(n \log n) (the complexity analysis appears below).

For example, given the sequence a=(5,1,4)a = (5, 1, 4), to build the tree we can treat it as a point addition of a[1]a[1] by 55, a point addition of a[2]a[2] by 11, and a point addition of a[3]a[3] by 44.

There is also an Θ(n)\Theta(n) tree-building method; see Tree building in Θ(n)\Theta(n) on this page.

Complexity analysis

The space complexity is clearly Θ(n)\Theta(n).

Time complexity:

  • For a range query: the entire iteration process x←x−lowbit⁡(x)x \gets x - \operatorname{lowbit}(x) can be viewed as gradually changing, from the lowest bit upward, the binary representation of xx so that every 11 becomes 00. The number of intervals decomposed equals the number of bit positions at which the binary representation of xx has value 11 (that is, popcount⁡(x)\operatorname{popcount}(x)). Therefore, the time complexity of one query is Θ(log⁡n)\Theta(\log n).
  • For a point update: when jumping to parents, the height of each visited node strictly increases, and x≤nx \le n always holds. Since the height of node xx is log⁡2lowbit⁡(x)\log_2\operatorname{lowbit}(x), the height reached cannot exceed log⁡2n\log_2n, so the number of visited cc values is on the order of log⁡n\log n. Therefore, the complexity of one point update is Θ(log⁡n)\Theta(\log n).

Range additions with range sums

Prerequisite: prefix sums & differences.

This problem can be solved with two Fenwick trees maintaining a difference array.

Consider sequence aa's difference array dd, where d[i]=a[i]−a[i−1]d[i] = a[i] - a[i - 1]. Since the prefix sum of the difference array is the original array, ai=∑j=1idja_i=\sum_{j=1}^i d_j.

Similarly, we convert a range-sum query into a prefix-sum query using differences. Consider the sum of a[1…r]a[1 \ldots r], namely ∑i=1rai\sum_{i=1}^{r} a_i, and derive it:

∑i=1rai=∑i=1r∑j=1idj\begin{aligned} &\sum_{i=1}^{r} a_i\\=&\sum_{i=1}^r\sum_{j=1}^i d_j \end{aligned}

Inspecting this expression, it is easy to see that each djd_j is added a total of r−j+1r - j + 1 times. Continuing the derivation:

∑i=1r∑j=1idj=∑i=1rdi×(r−i+1)=∑i=1rdi×(r+1)−∑i=1rdi×i\begin{aligned} &\sum_{i=1}^r\sum_{j=1}^i d_j\\=&\sum_{i=1}^r d_i\times(r-i+1) \\=&\sum_{i=1}^r d_i\times (r+1)-\sum_{i=1}^r d_i\times i \end{aligned}

∑i=1rdi\sum_{i=1}^r d_i does not determine the value of ∑i=1rdi×i\sum_{i=1}^r d_i \times i, so we need two Fenwick trees to maintain the sums of did_i and di×id_i \times i separately.

How do we perform a range addition? Consider how the original range a[l…r]a[l \ldots r] changes when adding xx, and how that affects dd.

Because the difference is d[i]=a[i]−a[i−1]d[i] = a[i] - a[i - 1],

  • a[l]a[l] increases by vv while a[l−1]a[l - 1] is unchanged, so d[l]d[l] increases by vv.
  • a[r+1]a[r + 1] is unchanged while a[r]a[r] increases by vv, so d[r+1]d[r + 1] decreases by vv.
  • For any positions other than ll and r+1r+1, namely ii, either a[i]a[i] and a[i−1]a[i - 1] both remain unchanged or both increase by vv. Thus a[i]+v−(a[i−1]+v)a[i] + v - (a[i - 1] + v) remains a[i]−a[i−1]a[i] - a[i - 1], so all other d[i]d[i] remain unchanged.

The maintenance method is now clear: in the Fenwick tree maintaining did_i, add at ll an amount vv and at r+1r + 1 an amount −v-v; in the Fenwick tree maintaining di×id_i \times i, add at ll an amount v×lv \times l and at r+1r + 1 an amount −v×(r+1)-v \times (r + 1).

For the weaker problem of “range addition, point-value query”, it is enough to use a Fenwick tree to maintain one difference array did_i. To query the point value at a[x]a[x], simply find the sum of d[1…x]d[1 \ldots x].

Here is the code for “range additions with range sums”:

Implementation

C++

int t1[MAXN], t2[MAXN], n;

int lowbit(int x) { return x & (-x); }

void add(int k, int v) {
  int v1 = k * v;
  while (k <= n) {
    t1[k] += v, t2[k] += v1;
    // Do not write t2[k] += k * v, because k is no longer an index in the original array
    k += lowbit(k);
  }
}

int getsum(int *t, int k) {
  int ret = 0;
  while (k) {
    ret += t[k];
    k -= lowbit(k);
  }
  return ret;
}

void add1(int l, int r, int v) {
  add(l, v), add(r + 1, -v);  // Convert a range addition into two prefix additions
}

long long getsum1(int l, int r) {
  return (r + 1ll) * getsum(t1, r) - 1ll * l * getsum(t1, l - 1) -
         (getsum(t2, r) - getsum(t2, l - 1));
}

Python

t1 = [0] * MAXN
t2 = [0] * MAXN
n = 0


def lowbit(x):
    return x & (-x)


def add(k, v):
    v1 = k * v
    while k <= n:
        t1[k] = t1[k] + v
        t2[k] = t2[k] + v1
        k = k + lowbit(k)


def getsum(t, k):
    ret = 0
    while k:
        ret = ret + t[k]
        k = k - lowbit(k)
    return ret


def add1(l, r, v):
    add(l, v)
    add(r + 1, -v)


def getsum1(l, r):
    return (
        (r) * getsum(t1, r)
        - l * getsum(t1, l - 1)
        - (getsum(t2, r) - getsum(t2, l - 1))
    )

Following this principle, one can implement “range multiplication with range products”, “XOR a number over a range and query the range XOR”, and so on, as long as the maintained information and the range operation use the same operation. Interested readers can try these themselves.

Two-dimensional Fenwick trees

Point updates, submatrix queries

A two-dimensional Fenwick tree, also called a Fenwick tree of Fenwick trees, maintains point updates and prefix information on a two-dimensional array.

As with a one-dimensional Fenwick tree, let c(x,y)c(x, y) denote the total matrix information for a(x−lowbit⁡(x)+1,y−lowbit⁡(y)+1)…a(x,y)a(x - \operatorname{lowbit}(x) + 1, y - \operatorname{lowbit}(y) + 1) \ldots a(x, y); that is, the total information of a matrix with a(x,y)a(x, y) as its lower-right corner, height lowbit⁡(x)\operatorname{lowbit}(x), and width lowbit⁡(y)\operatorname{lowbit}(y).

For a point update, let:

f(x,i)={xi=0f(x,i−1)+lowbit⁡(f(x,i−1))i>0f(x, i) = \begin{cases}x &i = 0\\f(x, i - 1) + \operatorname{lowbit}(f(x, i - 1)) & i > 0\\\end{cases}

That is, f(x,i)f(x, i) is the ancestor of xx at level ii in the Fenwick-tree structure (the level-00 ancestor is the node itself).

Then only elements in c(f(x,i),f(y,j))c(f(x, i), f(y, j)) govern a(x,y)a(x, y). When updating a(x,y)a(x, y), we only need to update every c(f(x,i),f(y,j))c(f(x, i), f(y, j)) with f(x,i)≤nf(x, i) \le n and f(y,j)≤mf(y, j) \le m.

Correctness proof

Suppose c(p,q)c(p, q) governs a(x,y)a(x, y). Find the possible values of pp and qq.

Consider a one-dimensional Fenwick tree of size nn, c1c_1 (corresponding to the original array a1a_1), and a one-dimensional Fenwick tree of size mm, c2c_2 (corresponding to the original array a2a_2).

The proposition is then equivalent to the condition that c1(p)c_1(p) governs a1[x]a_1[x] and c2(q)c_2(q) governs a2[y]a_2[y].

In other words, in the Fenwick-tree structure, pp is one of xx and its ancestors, and qq is one of yy and its ancestors.

Therefore, p=f(x,i)p = f(x, i) and q=f(y,j)q = f(y, j).

For a query, let:

g(x,i)={xi=0g(x,i−1)−lowbit⁡(g(x,i−1))i,g(x,i−1)>00otherwise.g(x, i) = \begin{cases}x &i = 0\\g(x, i - 1) - \operatorname{lowbit}(g(x, i - 1)) & i, g(x, i - 1) > 0\\0&\text{otherwise.}\end{cases}

Then combine every c(g(x,i),g(y,j))c(g(x, i), g(y, j)) for which g(x,i),g(y,j)>0g(x, i), g(y, j) > 0.

Correctness proof

Let ∘\circ denote the operation used to combine two pieces of information (for example, if the information is a range sum, then ∘=+\circ = +).

Consider a one-dimensional Fenwick tree c1c_1. The expression c1[g(x,0)]∘c1[g(x,1)]∘c1[g(x,2)]∘⋯c_1[g(x, 0)] \circ c_1[g(x, 1)] \circ c_1[g(x, 2)] \circ \cdots exactly represents the information for the interval [1…x][1 \ldots x] of the original array.

Similarly, let t(x)=c(x,g(y,0))∘c(x,g(y,1))∘c(x,g(y,2))∘⋯t(x) = c(x, g(y, 0)) \circ c(x, g(y, 1)) \circ c(x, g(y, 2)) \circ \cdots. Then t(x)t(x) exactly represents the matrix information of a(x−lowbit⁡(x)+1,1)…a(x,y)a(x - \operatorname{lowbit}(x) + 1, 1) \ldots a(x, y).

Likewise, t(g(x,0))∘t(g(x,1))∘t(g(x,2))∘⋯t(g(x, 0)) \circ t(g(x, 1)) \circ t(g(x, 2)) \circ \cdots represents the matrix information of a(1,1)…a(x,y)a(1, 1) \ldots a(x, y).

If we regard the function t(x)t(x) as a Fenwick tree, it is effectively a Fenwick tree of Fenwick trees; this is the origin of the name “Fenwick tree of Fenwick trees”.

Here is the code for point additions and submatrix-sum queries.

Implementation

Point addition

void add(int x, int y, int v) {
  for (int i = x; i <= n; i += lowbit(i)) {
    for (int j = y; j <= m; j += lowbit(j)) {
      // A loop variable must be created here; unlike in a one-dimensional array, we cannot simply write while (x <= n)
      c[i][j] += v;
    }
  }
}

Submatrix-sum query

int sum(int x, int y) {
  int res = 0;
  for (int i = x; i > 0; i -= lowbit(i)) {
    for (int j = y; j > 0; j -= lowbit(j)) {
      res += c[i][j];
    }
  }
  return res;
}

int ask(int x1, int y1, int x2, int y2) {
  // Query the submatrix sum
  return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1);
}

Submatrix additions, submatrix-sum queries

Prerequisites: prefix sums & differences and the range additions with range sums section on this page.

As with the one-dimensional Fenwick-tree problem of range additions with range sums, consider maintaining a difference array.

The difference array of a two-dimensional array is defined as follows:

d(i,j)=a(i,j)−a(i−1,j)−a(i,j−1)+a(i−1,j−1).d(i, j) = a(i, j) - a(i - 1, j) - a(i, j - 1) + a(i - 1, j - 1).
Why is it defined this way?

This is because, in the ideal state, taking a two-dimensional prefix sum over the difference matrix should recover the original matrix: the two operations are inverses.

The two-dimensional prefix-sum formula is:

s(i,j)=s(i−1,j)+s(i,j−1)−s(i−1,j−1)+a(i,j)s(i, j) = s(i - 1, j) + s(i, j - 1) - s(i - 1, j - 1) + a(i, j).

Thus, let aa be the original array and dd the difference array. We have:

a(i,j)=a(i−1,j)+a(i,j−1)−a(i−1,j−1)+d(i,j)a(i, j) = a(i - 1, j) + a(i, j - 1) - a(i - 1, j - 1) + d(i, j)

Rearranging gives the formula for two-dimensional differences.

d(i,j)=a(i,j)−a(i−1,j)−a(i,j−1)+a(i−1,j−1)d(i, j) = a(i, j) - a(i - 1, j) - a(i, j - 1) + a(i - 1, j - 1).

Thus, for the submatrix whose upper-left corner is (x1,y1)(x_1, y_1) and lower-right corner is (x2,y2)(x_2, y_2), a submatrix addition of vv is equivalent, on the difference array, to adding at d(x1,y1)d(x_1, y_1) and d(x2+1,y2+1)d(x_2 + 1, y_2 + 1) an amount vv, and adding at d(x2+1,y1)d(x_2 + 1, y_1) and d(x1,y2+1)d(x_1, y_2 + 1) an amount −v-v.

As for why this works, write these four dd values using their defining formulas and analyze the change in each term.

Consider an example. If the initial difference array is 00 and the submatrix a(2,2)…a(3,4)a(2, 2) \ldots a(3, 4) receives an addition of vv, the difference array becomes:

(000000v00−v000000−v00v)\begin{pmatrix}0&0&0&0&0\\0&v&0&0&-v\\0&0&0&0&0\\0&-v&0&0&v\end{pmatrix}

(The submatrix a(2,2)…a(3,4)a(2, 2) \ldots a(3, 4) is exactly the central matrix of size 2×32 \times 3 shown above.)

Therefore, a submatrix addition is implemented as four point additions on the difference array.

Now consider a submatrix-sum query:

For a point (x,y)(x, y), its two-dimensional prefix sum can be written as:

∑i=1x∑j=1y∑h=1i∑k=1jd(h,k)\sum_{i = 1}^x\sum_{j = 1}^y\sum_{h = 1}^i\sum_{k = 1}^j d(h, k)

The reason is that the prefix sum of the prefix sum of the difference array is the original prefix sum.

As with the one-dimensional range-addition/range-sum problem, the number of occurrences of d(h,k)d(h, k) is (x−h+1)×(y−k+1)(x - h + 1) \times (y - k + 1).

Continuing the derivation:

∑i=1x∑j=1y∑h=1i∑k=1jd(h,k)=∑i=1x∑j=1yd(i,j)×(x−i+1)×(y−j+1)=∑i=1x∑j=1yd(i,j)×(xy+x+y+1)−d(i,j)×i×(y+1)−d(i,j)×j×(x+1)+d(i,j)×i×j\begin{aligned} &\sum_{i = 1}^x\sum_{j = 1}^y\sum_{h = 1}^i\sum_{k = 1}^j d(h, k) \\=&\sum_{i = 1}^x\sum_{j = 1}^y d(i, j) \times (x - i + 1) \times (y - j + 1) \\=&\sum_{i = 1}^x\sum_{j = 1}^y d(i, j) \times (xy + x + y + 1) - d(i, j) \times i \times (y + 1) - d(i, j) \times j \times (x + 1) + d(i, j) \times i \times j \end{aligned}

Therefore, we need four Fenwick trees, maintaining the sums of d(i,j)d(i, j), d(i,j)×id(i, j) \times i, d(i,j)×jd(i, j) \times j, and d(i,j)×i×jd(i, j) \times i \times j, respectively.

As in the one-dimensional case, if we only need submatrix additions and point-value queries, maintaining one difference array and querying its prefix sum is enough.

Here is the code:

Implementation
using ll = long long;
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];

void add(ll x, ll y, ll z) {
  for (int X = x; X <= n; X += lowbit(X))
    for (int Y = y; Y <= m; Y += lowbit(Y)) {
      t1[X][Y] += z;
      t2[X][Y] += z * x;  // Note that this is z * x rather than z * X; the same applies below
      t3[X][Y] += z * y;
      t4[X][Y] += z * x * y;
    }
}

void range_add(ll xa, ll ya, ll xb, ll yb,
               ll z) {  //(xa, ya) to (xb, yb) submatrix
  add(xa, ya, z);
  add(xa, yb + 1, -z);
  add(xb + 1, ya, -z);
  add(xb + 1, yb + 1, z);
}

ll ask(ll x, ll y) {
  ll res = 0;
  for (int i = x; i; i -= lowbit(i))
    for (int j = y; j; j -= lowbit(j))
      res += (x + 1) * (y + 1) * t1[i][j] - (y + 1) * t2[i][j] -
             (x + 1) * t3[i][j] + t4[i][j];
  return res;
}

ll range_ask(ll xa, ll ya, ll xb, ll yb) {
  return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}

Weighted Fenwick trees and applications

We know that when a standard Fenwick tree is built directly on the original sequence, c6c_6 represents the range information of a[5…6]a[5 \ldots 6].

In fact, we can also build a Fenwick tree over the value-frequency array of the original sequence; this is a weighted Fenwick tree.

What is a value-frequency array?

For a sequence aa, its value-frequency array bb satisfies: the value of b[x]b[x] is the number of occurrences of xx in aa.

For example, the value-frequency array of a=(1,3,4,3,4)a = (1, 3, 4, 3, 4) is b=(1,0,2,2)b = (1, 0, 2, 2).

Clearly, the size of bb is related to the value range of aa.

If the value range of the original sequence is too large and only relative order matters rather than the exact values, the original array is often discretized before building the value-frequency array.

In addition, a value-frequency array represents the order-insensitive content of the original array: it describes the elements while ignoring their order, so two arrays with the same content in different orders have the same value-frequency array.

Therefore, for problems whose answers do not depend on the order of a given array, reasoning with the value-frequency array is often more intuitive, such as [NOIP2021] Sequence.

Using weighted Fenwick trees, we can solve several classic problems.

Point updates, querying the global kk-th smallest

Here we discuss only the kk-th smallest; the kk-th largest problem can be converted to the kk-th smallest by a simple calculation.

This problem can be discretized. If the value range of the original sequence aa is too large, discretize it and then build the value-frequency array bb. The values involved in point updates must also be discretized; it is not enough to discretize only the elements of the original array aa.

A point update on the original sequence can be converted directly into a point update on the value-frequency array. Specifically, changing the original value a[x]a[x] from yy to zz becomes a point update on bb: at b[y]b[y], subtract 11; at b[z]b[z], add 11.

To query the kk-th smallest, binary-search xx and query the prefix sum of [1,x][1, x] in the value-frequency array. Find x0x_0 such that the prefix sum of [1,x0][1, x_0] is <k< k while that of [1,x0+1][1, x_0 + 1] is ≥k\ge k; then the kk-th largest number is x0+1x_0 + 1 (note: here the prefix sum of [1,0][1, 0] is regarded as 00).

This gives a time complexity of Θ(log⁡2n)\Theta(\log^2n).

Consider replacing binary search with binary lifting.

Set x=0x = 0 and sum=0\mathrm{sum} = 0, then enumerate ii downward from log⁡2n\log_2n to 00:

  • Query the range sum of [x+1…x+2i][x + 1 \ldots x + 2^i] in the value-frequency array, denoted tt.
  • If sum+t<k\mathrm{sum} + t < k, the extension succeeds: set x←x+2ix \gets x + 2^i and sum←sum+t\mathrm{sum} \gets \mathrm{sum} + t; otherwise, the extension fails and nothing is done.

The resulting xx is the maximum value for which the prefix sum of [1…x][1 \ldots x] is <k< k, so the final answer is x+1x + 1.

This may appear not to improve the time efficiency, but in fact the range sum query for [x+1…x+2i][x + 1 \ldots x + 2^i] only needs to access the value of c[x+2i]c[x + 2^i].

The reason is simple. Consider lowbit⁡(x+2i)\operatorname{lowbit}(x + 2^i): it must be 2i2^i, because before xx we only added 2j2^j with j>ij > i. Therefore, the interval represented by c[x+2i]c[x + 2^i] is exactly [x+1…x+2i][x + 1 \ldots x + 2^i].

Thus, the time complexity decreases to Θ(log⁡n)\Theta(\log n).

Implementation

C++

// Query the k-th smallest in a weighted Fenwick tree
int kth(int k) {
  int sum = 0, x = 0;
  for (int i = log2(n); ~i; --i) {
    x += 1 << i;                   // Try to extend
    if (x > n || sum + t[x] >= k)  // Extension failed
      x -= 1 << i;
    else
      sum += t[x];
  }
  return x + 1;  // Return n + 1 if it cannot be found
}

Python

# Query the k-th smallest in a weighted Fenwick tree
def kth(k):
    sum = 0
    x = 0
    i = int(log2(n))
    while ~i:
        x = x + (1 << i)  # Try to extend
        if x > n or sum + t[x] >= k:  # Extension failed
            x = x - (1 << i)
        else:
            sum = sum + t[x]
        i = i - 1
    return x + 1  # Return n + 1 if it cannot be found

Global inversions (global two-dimensional partial order)

Related reading and reference implementation: inversions

Global inversions can also be solved elegantly with a weighted Fenwick tree. The problem is: given nn, the length of a sequence aa, count the pairs in aa satisfying i<ji < j and a[i]>a[j]a[i] > a[j], written as (i,j)(i, j).

This problem can be discretized. If the value range of the original sequence aa is too large, discretize it and then build the value-frequency array bb.

We enumerate in reverse from nn down to 11 using index ii, treating it as the index of the first element of an inversion. We then count how many j>ij > i satisfy a[j]<a[i]a[j] < a[i], and accumulate the answer.

In fact, we only need to do the following (let the current a[i]=xa[i] = x):

  • Query the prefix sum of b[1…x−1]b[1 \ldots x - 1], which is the number of inversions whose left endpoint is a[i]a[i].
  • Increase b[x]b[x] by 11;

The reason is natural: every element appearing in b[1…x−1]b[1 \ldots x-1] is smaller than the current x=a[i]x = a[i]. Because ii is enumerated in reverse, these elements already in the value-frequency array naturally have original-array indices jj greater than the index ii currently being visited.

As an example, let a=(4,3,1,2,1)a = (4, 3, 1, 2, 1).

We scan ii in the order 5→15 \to 1:

  • a[5]=1a[5] = 1: query the prefix sum of b[1…0]b[1 \ldots 0], obtaining 00; increase b[1]b[1] by 11, giving b=(1,0,0,0)b = (1, 0, 0, 0).
  • a[4]=2a[4] = 2: query the prefix sum of b[1…1]b[1 \ldots 1], obtaining 11; increase b[2]b[2] by 11, giving b=(1,1,0,0)b = (1, 1, 0, 0).
  • a[3]=1a[3] = 1: query the prefix sum of b[1…0]b[1 \ldots 0], obtaining 00; increase b[1]b[1] by 11, giving b=(2,1,0,0)b = (2, 1, 0, 0).
  • a[2]=3a[2] = 3: query the prefix sum of b[1…2]b[1 \ldots 2], obtaining 33; increase b[3]b[3] by 11, giving b=(2,1,1,0)b = (2, 1, 1, 0).
  • a[1]=4a[1] = 4: query the prefix sum of b[1…3]b[1 \ldots 3], obtaining 44; increase b[4]b[4] by 11, giving b=(2,1,1,1)b = (2, 1, 1, 1).

Therefore, the final answer is 0+1+0+3+4=80 + 1 + 0 + 3 + 4 = 8.

Notice that after enumerating ii, the two steps—querying b[1…x−1]b[1 \ldots x - 1] and increasing b[x]b[x]—can be reversed: increase b[x]b[x] first, then query b[1…x−1]b[1 \ldots x - 1], without changing the answer. There are two ways to see this:

  • Updating b[x]b[x] does not affect the query on b[1…x−1]b[1 \ldots x - 1].
  • After reversal, we are effectively counting pairs with i≤ji \le j and a[i]>a[j]a[i] > a[j]. When i=ji = j, a[i]>a[j]a[i] > a[j] is impossible, so i≤ji \le j is equivalent to i<ji < j; this is therefore equivalent to the original inversion problem.

If we query the number of non-strict inversions (i<ji < j and a[i]≥a[j]a[i] \ge a[j]), we must instead query the sum of b[1…x]b[1 \ldots x], and the two steps can no longer be reversed. Again, there are two ways to see this:

  • A modification to b[x]b[x] affects queries on b[1…x]b[1 \ldots x].
  • After reversing the process, what is actually being queried is the number of pairs satisfying i≤ji \le j and a[i]≥a[j]a[i] \ge a[j]. Since a[i]≥a[j]a[i] \ge a[j] always holds when i=ji = j, i≤ji \le j is not equivalent to i<ji < j, so this is not equivalent to the original problem.

If we want to query the number of pairs satisfying i≤ji \le j and a[i]≥a[j]a[i] \ge a[j], these two steps need to be reversed.

Another way to solve the original inversion-pair problem is to enumerate jj in increasing order and query how many i<ji < j satisfy a[i]>a[j]a[i] > a[j]. The procedure is as follows (let x=a[j]x = a[j]):

  • Query the interval sum of b[x+1…V]b[x + 1 \ldots V] (VV is the size of bb, namely the value range of aa (or its discretized value range)).
  • Increment b[x]b[x] by 11.

The reason is that every element appearing in b[x+1…V]b[x + 1 \ldots V] is greater than the current x=a[j]x = a[j]. Since jj is enumerated in increasing order, these elements already stored in the value array naturally have original-array indices ii smaller than the currently visited index jj.

In addition, inversion pairs can also be counted using merge sort. This method avoids discretization. Its time complexity is likewise O(nlog⁡n)O(n\log n). Reference implementations of both algorithms can be found in the inversion pairs section.

Fenwick tree maintenance of non-invertible information

For example, maintaining interval extrema.

Although this method uses little code, note that both point updates and interval queries have time complexity Θ(log⁡2n)\Theta(\log^2n), which is worse than the Θ(log⁡n)\Theta(\log n) time complexity of a segment tree.

Interval queries

We still follow the previous idea: starting from rr, repeatedly jump forward along lowbit⁡\operatorname{lowbit}, but we must not jump to the left of ll.

Therefore, if we have jumped to c[x]c[x], first determine whether the next position, x−lowbit⁡(x)x - \operatorname{lowbit}(x), would be less than ll:

  • If it is less than ll, we directly merge the single point a[x]\boldsymbol{a[x]} into the aggregate information, and then jump to c[x−1]c[x - 1].
  • If it is greater than or equal to ll, no boundary has been crossed, so merge c[x]c[x] normally and then jump to c[x−lowbit⁡(x)]c[x - \operatorname{lowbit}(x)].

Here is the code, using an interval maximum query as an example:

Implementation
int getmax(int l, int r) {
  int ans = 0;
  while (r >= l) {
    ans = max(ans, a[r]);
    --r;
    for (; r - lowbit(r) >= l; r -= lowbit(r)) {
      // Note that the loop condition must not be written as r - lowbit(r) + 1 >= l
      // Otherwise, when l = 1, r will jump to 0 and enter an infinite loop
      ans = max(ans, C[r]);
    }
  }
  return ans;
}

It can be proved that the time complexity of the above algorithm is Θ(log⁡2n)\Theta(\log^2n).

Time complexity proof

Consider the highest bit at which rr and ll differ. At this bit, rr must contain 11 and ll must contain 00 (because r≥lr \ge l).

If rr still has a 11 after this bit, then r−lowbit⁡(r)≥lr - \operatorname{lowbit}(r) \ge l must hold, so the next step must fill the lowest 11 bit of rr with 00;

If the 11 at this bit of rr is itself the lowest 11 bit of rr, then whether we perform r←r−lowbit⁡(r)r \gets r - \operatorname{lowbit}(r) or r←r−1r \gets r - 1, the 11 at this bit of rr will become 00.

Therefore, after at most log⁡n\log n transformations of rr, the highest bit at which rr and ll differ must decrease by one. Thus, the total time complexity is Θ(log⁡2n)\Theta(\log^2n).

Point updates

Note

Please first understand the following two properties of the Fenwick tree structure before studying this section.

  • Let u=s×2k+1+2ku = s \times 2^{k + 1} + 2^k. Then it has k=log⁡2lowbit⁡(u)k = \log_2\operatorname{lowbit}(u) children, whose indices are respectively u−2t(0≤t<k)u - 2^t(0 \le t < k).
  • The intervals governed by cc corresponding to all children of uu concatenate exactly into [l(u),u−1][l(u), u - 1].

The meaning and proof of these two properties can be found in the section Fenwick tree and properties of its tree structure on this page.

After updating a[x]a[x], we only need to update those c[y]c[y] for which yy is an ancestor of xx in the Fenwick tree structure.

For extrema (taking the maximum as an example), a common incorrect idea is that if a[x]a[x] is changed to pp, then every c[y]c[y] should be updated to max⁡(c[y],p)\max(c[y], p). Here is a counterexample: change 55 to 44 in (1,2,3,4,5)(1, 2, 3, 4, 5). The maximum is 44, but the update above would produce 55. Directly changing c[y]c[y] to pp is also incorrect; a counterexample is to change 33 to 44 in the example above.

In fact, for non-invertible information, there is no way to directly modify c[y]c[y] using pp. This is because a modification is equivalent to removing the old number from the original interval and then adding a new number. The effect of removing it on the interval information is equivalent to performing an inverse operation, but non-invertible information has no inverse operation, so c[y]c[y] cannot be modified directly.

In other words, for every affected c[y]c[y], we must reconstruct the information for that interval.

Consider the children of c[y]c[y]. Their information is necessarily correct (because we update the children before the parent), and these children together form the governed interval [l(y),y−1][l(y), y - 1]. Merging one more single point, a[y]a[y], therefore produces [l(y),y][l(y), y], which is precisely c[y]c[y]. In this way, we can reconstruct and merge at most log⁡n\log n intervals to obtain each cc that needs to be updated.

Implementation
void update(int x, int v) {
  a[x] = v;
  for (int i = x; i <= n; i += lowbit(i)) {
    // Enumerate the affected intervals
    C[i] = a[i];
    for (int j = 1; j < lowbit(i); j *= 2) {
      C[i] = max(C[i], C[i - j]);
    }
  }
}

It is easy to see that the time complexity of the above algorithm is Θ(log⁡2n)\Theta(\log^2n).

Building the tree

We can split this into nn single-point updates, giving a construction complexity of Θ(nlog⁡2n)\Theta(n\log^2n).

There is also an Θ(n)\Theta(n) construction method; see method one in the Θ(n)\Theta(n) tree construction section of this page.

Tricks

Θ(n)\Theta(n) tree construction

Take maintaining interval sums as an example.

Method one:

The value of each node is obtained by summing the values of all its directly connected children. Therefore, we can consider the contributions in reverse: after determining a child's value, use it to update its direct parent.

Implementation

C++

// Θ(n) tree construction
void init() {
  for (int i = 1; i <= n; ++i) {
    t[i] += a[i];
    int j = i + lowbit(i);
    if (j <= n) t[j] += t[i];
  }
}

Python

# Θ(n) tree construction
def init():
    for i in range(1, n + 1):
        t[i] = t[i] + a[i]
        j = i + lowbit(i)
        if j <= n:
            t[j] = t[j] + t[i]

Method two:

As mentioned earlier, the interval represented by c[i]c[i] is [i−lowbit⁡(i)+1,i][i-\operatorname{lowbit}(i)+1, i]. We can therefore precompute a prefix-sum array sum\mathrm{sum} and then calculate the cc array.

Implementation

C++

// Θ(n) tree construction
void init() {
  for (int i = 1; i <= n; ++i) {
    t[i] = sum[i] - sum[i - lowbit(i)];
  }
}

Python

# Θ(n) tree construction
def init():
    for i in range(1, n + 1):
        t[i] = sum[i] - sum[i - lowbit(i)]

Timestamp optimization

This is a common technique for handling multiple data sets. If we clear the Fenwick tree by brute force every time new data is input, a time limit may be exceeded. We therefore use a tag\mathrm{tag} marker to store the last time each node was used (that is, which data set most recently used it). During each operation, compare the time in this position's tag\mathrm{tag} with the current time to determine whether the position should contain 00 or its value in the array.

Implementation

C++

// Timestamp optimization
int tag[MAXN], t[MAXN], Tag;

void reset() { ++Tag; }

void add(int k, int v) {
  while (k <= n) {
    if (tag[k] != Tag) t[k] = 0;
    t[k] += v, tag[k] = Tag;
    k += lowbit(k);
  }
}

int getsum(int k) {
  int ret = 0;
  while (k) {
    if (tag[k] == Tag) ret += t[k];
    k -= lowbit(k);
  }
  return ret;
}

Python

# Timestamp optimization
tag = [0] * MAXN
t = [0] * MAXN
Tag = 0


def reset():
    Tag = Tag + 1


def add(k, v):
    while k <= n:
        if tag[k] != Tag:
            t[k] = 0
        t[k] = t[k] + v
        tag[k] = Tag
        k = k + lowbit(k)


def getsum(k):
    ret = 0
    while k:
        if tag[k] == Tag:
            ret = ret + t[k]
        k = k - lowbit(k)
    return ret

Example problems

This content comes from OI Wiki: Fenwick Tree. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.