How to implement segment trees with lazy propagation?

后端 未结 5 1372
刺人心
刺人心 2021-01-30 05:25

I have searched on internet about implementation of Segment trees but found nothing when it came to lazy propagation. There were some previous questions on stack overflow but th

5条回答
  •  谎友^
    谎友^ (楼主)
    2021-01-30 06:16

    There doesn't seem to be any advantage in making the segment trees lazy. Eventually you will need to look at the ends of each unit slope segment to get the min and max. So you might as well expand them eagerly.

    Rather, just modify the standard segment tree definition. The intervals in the tree will each have an extra integer d stored with them, so we'll write [d; lo,hi]. The tree has the following operations:

    init(T, hi) // make a segment tree for the interval [0; 1,hi]
    split(T, x, d)  // given there exists some interval [e; lo,hi],
                    // in T where lo < x <= hi, replace this interval
                    // with 2 new ones [e; lo,x-1] and [d; x,hi];
                    // if x==lo, then replace with [e+d; lo,hi]
    

    Now after initializing we handle the addition of d to subinterval [lo,hi] with two split operations:

    split(T, lo, d); split(T, hi+1, -d);
    

    The idea here is we are adding d to everything at position lo and to the right and subtracting it out again for hi+1 and right.

    After the tree is constructed, a single left-to-right pass over the leaves lets us find the values at the ends of unit slope segments of integers. This is all we need to compute the min and max values. More formally, if the leaf intervals of the tree are [d_i; lo_i,hi_i], i=1..n in left to right order, then we want to compute running difference D_i = sum{i=1..n} d_i and then L_i = lo_i + D_i and H_i = hi_i + D_i. In the example, we start with [0; 1,10] and then split at 4 with d=-4 and 7 with d=+4 to obtain [0; 1,2] [-4; 3,6] [4; 7,10]. Then L = [1,-1,7] and H = [2, 2, 10]. So min is -1 and max is 10. This is a trivial example, but it will work in general.

    Run time will be O( min (k log N, k^2) ) where N is the maximum initial range value (10 in the example) and k is the number of operations applied. The k^2 case occurs if you have very bad luck in ordering of splits. If you randomize the list of operations, the expected time will be O(k min (log N, log k)).

    If you are interested, I can code this up for you. But I won't if there is no interest.

提交回复
热议问题