Fenwick Tree in 5 minutes
Разница между en3 и en4, 153 символ(ов) изменены
Fenwick Tree in 5 minutes↵
==================↵
↵
Fenwick tree is a dynamic prefix sums array. You can:↵
↵
- Add values to elements in $O(\log N)$↵
- Get prefix sum in $O(\log N)$↵
↵
Structure↵
------------------↵
↵
Fenwick tree is a single array. Each element $i$ has sum of elements on some range. Each range ends in its element, but they have different sizes.↵
↵
Here's how the segments look for each element:↵
↵
![ ](/predownloaded/fe/8b/fe8ba4034ac962b8ea8b09cbfd16bf3b6ad067dc.png)↵
↵
See a pattern? Sizes of ranges go like $1, 2, 1, 4, 1, 2, 1, 8, \dots$↵
↵
How do we get size of range for element $i$?↵
↵
<spoiler summary="Answer">↵
Look at binary representation of index $i$:↵
↵
$${11}_{10} = {1011}_2$$↵
↵
We can count the number of consecutive ones on the right side (least significant bits). Say this number is $k$. Then the size of the range is $2^k$.↵
</spoiler>↵
↵
So each element in fenwick array will keep the sum of its segment. Initially the array is filled with zeroes.↵
↵
Adding Values↵
------------------↵
↵
What happens when you add $x$ to element at position $i$? You need to increment ${tre}[i]$ by $x$. But also, you need to update other ranges that contain this position. How do we find them?↵
↵
![ ](/predownloaded/74/d0/74d036ddb76025c69256188f687e6c6a15658699.png)↵
↵
<spoiler summary="Answer">↵
Look at binary representation of $i$ again. What is the next index, where the range contains this element? Its the same index, but with the first $0$ from the right (least significant) replaced with a $1$:↵
↵
↵
$$1011\mathbf{0}111 \rightarrow 1011\mathbf{1}111$$↵
</spoiler>↵
↵
To find such index we'll use some binary magic. Try to figure this out for yourself.↵
↵
<spoiler summary="Answer">↵
What happens when you add $1$ to your index $i$ in binary? All consecutive ones turn into zeroes and the first zero becomes a one:↵
↵
↵
$$1011\mathbf{0111} + 1 = 1011\mathbf{1000}$$↵
↵
So if we take bitwise OR of the two, we'll get the desired index.↵
↵
~~~~~↵
inline void add(int i, int x)↵
{↵
    for(; i < MAXN; i |= (i+1)) ↵
    {↵
        tre[i] += x;↵
    }↵
}↵
~~~~~↵
</spoiler>↵
↵
Getting Prefix Sum↵
------------------↵
↵
To get prefix sum of first $i$ elements, we'll start at position $i-1$. We'll take the sum on the range for that index, and jump to the next index.
 ↵
↵
![ ](/predownloaded/99/74/9974160113aff83857231c2971510b08bcda0e8c.png)↵
↵
To do that, we simply subtract the range size. But, there is a cleaner solution, using bitwise magic again.↵
↵
<spoiler summary="Answer">↵
Look at binary. If length of the consecutive segment of ones is $k$, what does subtracting $2^k$ look like? The segment of ones itself has value $1 + 2 + \dots = 2^k-1$. So we can turn all those ones into zeroes, and then simply subtract a one.↵
↵
How do we remove the segment of ones? Same way we did before. We'll take $i$ and $i+1$, but instead of ORing them, we will AND them.↵
↵
~~~~~↵
int sum(int r)↵
{↵
    r--;↵
    int res = 0;↵
    for(; r >= 0; r = (r & (r+1))-1)↵
    {↵
        res += tre[r];↵
    }↵
    return res;↵
}↵
~~~~~↵
↵
</spoiler>↵
↵
Time Complexity↵
------------------↵
↵
As i said at the start, time complexity for both operations is $O(\log N)$. Why?↵
↵
- For addition, every iteration turns one bit into a one. So number of iterations is at most number of bits, which is $O(\log N)$.↵
- For sum, every iteration increases the size of the segment of ones. So number of iterations is also at most number of bits. $O(\log N)$↵
↵
Full Code↵
------------------↵
↵
~~~~~↵
const int MAXN = 200005;↵
↵
struct fenwick↵
{↵
    int tre[MAXN];↵
 ↵
    fenwick() {}↵
 ↵
    inline void clear(int n)↵
    {↵
        for(int i = 0; i < n; i++)↵
        {↵
            tre[i] = 0;↵
        }↵
    }↵
 ↵
    inline void add(int i, int x)↵
    {↵
        for(; i < MAXN; i |= (i+1))↵
        {↵
            tre[i] += x;↵
        }↵
    }↵
 ↵
    inline int sum(int r)↵
    {↵
        r--;↵
        int res = 0;↵
        for(; r >= 0; r = (r & (r+1))-1)↵
        {↵
            res += tre[r];↵
        }↵
        return res;↵
    }↵
};↵
~~~~~↵
↵
Conclusion↵
------------------↵
↵
Fenwick tree is used to keep a dynamic prefix sums array with every operation being $O(\log N)$.↵
↵
<spoiler summary="Can it be used for other prefix values, like minimum or maximum?">↵
Yes, but you can't really **set** individual values, you can only update them (i.e. min= or max= )↵
</spoiler>↵
↵
<spoiler summary="What about segment trees?">↵
Segment trees are far more versatile, but the implementation for fenwick tree is much simpler and faster.↵
</spoiler>↵
↵
<spoiler summary="Can i get a Bolba?">↵
Sure you can:↵
↵
![ ](/predownloaded/ed/8f/ed8fae5376aa08cb36733c0caf4a7c807c61af31.png)↵
↵
</spoiler>↵
↵

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en4 Английский Jajceslav 2026-06-29 01:21:21 153 Added more pictures
en3 Английский Jajceslav 2026-06-29 01:12:18 52 Tiny change: 'f{0}111 \rarrow 1011' -> 'f{0}111 \rightarrow 1011' (published)
en2 Английский Jajceslav 2026-06-29 01:02:24 81
en1 Английский Jajceslav 2026-06-29 01:01:51 4500 Initial revision (saved to drafts)