2

These sources cp-algorithms and geeksforgeeks state that query complexity (for example, submatrix sum) of 2-D segment tree is O(logN * logM), because

it first descends the tree in the first coordinate, and for each traversed vertex of that tree, it makes a query from the usual tree of segments along the second coordinate

However, in all implementations I have met, a query descends the tree along the second coordinate only when it reaches some node of the first tree (cannot recurse any further). Next, since there are no more than 4 recursive calls per level of a segment tree during a query, there would be no more than 4 queries along the second coordinate in total. So, in my view, the rime complexity should be O(logN + logM). What do I miss?

1 Answers1

0

*All logs are base 2

Because in its simplest implementation a 2d segment tree is a segment tree (along one dimension) with the nodes being segment trees as well (aligned with the other dimension), a query can be thought of as a query of a normal segment tree once nodes making up the range that would be included in a range query then a subsequent query in the other direction of each segment found. e.g. in a query [2, 7], 1,4-- with the first range corresponding to the first dimension-- the segment queried would be returned as the union of the segment trees representing [2,3] and [4,7]. After these have been located each is then queried with regard to the second dimension. While you are correct in that the first step takes O(log(N)) time and is completely independent of the latter step, the O(log(M)) step is performed a number of times equal to the number of small segments returned in the first step, which can be up to log N hence the overall complexity is O(log(N) x log(M)).

If one is not convinced that the number of segments making up a range in a segment tree, consider the query of a 0-indexed array: [1,7]. Since [1,1] is the right child of the tree it cannot be expanded. Likewise [2,3] is the right child of a segment tree on the next level hence no larger range can include it without including [0] which is not part of our tree. This line of thinking is extended and for a query of the form [1, (2^k)-1] we have trees of sizes 1,2,4...2^(k-2), 2^(k-1) = k trees = log(N). Notice that it is not a co-incidence that these correspond to the binary representation of the number (only in this case, however).

However, also note that the case laid out above is not the worst case (rather [1, 2^(k)-2] is the worst case) for the number of segments making up a query in a segment tree; however, the reason for this is that it forces the worst case for the two trees on the level below the root causing similar behavior as before. The worst case is thus can be bounded by 2*(log(N/2)) = 2*(log(N) -1) for all k>1 (rounding up to the nearest k for all trees not a power of 2)