Search code examples
algorithmdata-structuresfenwick-tree

Need a clear explanation of Range updates and range queries Binary indexed tree


I have gone through few tutorials of Range update - Range queries of Binary indexed tree. I'm unable to understand any of them. I don't understand the need of building another tree.

Could someone explain it to me in plain English with an example?


Solution

  • Trying to explain in more intuitive way (the way I understood). I'll divide it in four steps:

    Assume the update is between A and B with V and the query is a prefix query for any index <=X

    The first range update/point query tree (T1)

    The first is a simple range update/point query tree. When you update A to B with V, in practice you add V to position A, so any prefix query X>=A is affected by it. Then you remove V from B+1, so any query X >= B+1 doesn't see the V added to A. No surprises here.

    Prefix query to the range update/point tree

    The T1.sum(X) is a point query to this first tree at X. We optimistically assume then that every element before X is equal to the value at X. That's why we do T1.sum(X)*X. Obviously this isn't quite right, that's why we:

    Use a modified range update/point query tree to fix the result (T2)

    When updating the range, we also update a second tree to tell how much we have to fix the first T1.sum(X)*X query. This update consists in removing (A-1)*V from any query X>=A. Then we add back B*V for X>=B. We do the latter because queries to the first tree won't return V for X>=B+1 (because of the T1.add(B+1, -V)), so we need to somehow tell that there is a rectangle of area (B-A+1)*V for any query X>=B+1. We already removed (A-1)*V from A, we only need to add back B*V to B+1.

    Wrapping it all together

    update(A, B, V):
        T1.add(A, V)         # add V to any X>=A
        T1.add(B+1, -V)      # cancel previously added V from any X>=B+1
    
        T2.add(A, (A-1)*V)   # add a fix for (A-1)s V that didn't exist before A
        T2.add(B+1, -B*V)    # remove the fix, and add more (B-A+1)*V to any query 
                             # X>=B+1. This is really -(A-1)*V -(B-A+1)*V, but it 
                             # simplifies to -B*V
    
    sum(X):
        return T1.sum(X)*X - T2.sum(X)