This is my first attempt at writing something useful, so your suggestions are welcome.

Most participants of programming contests are familiar with segment trees to some degree, especially having read this articles http://codeforces.com/blog/entry/15890, http://e-maxx.ru/algo/segment_tree (Russian only). If you're not — don't go there yet. I advise to read them after this article for the sake of examples, and to compare implementations and choose the one you like more (will be kinda obvious).

Segment tree with single element modifications

Let's start with a brief explanation of segment trees. They are used when we have an array, perform some changes and queries on continuous segments. In the first example we'll consider 2 operations:

modify one element in the array;

find the sum of elements on some segment. .

Perfect binary tree

Notation is node_index: corresponding segment (left border included, right excluded). At the bottom row we have our array (0-indexed), the leaves of the tree. For now suppose it's length is a power of 2 (16 in the example), so we get perfect binary tree. When going up the tree we take pairs of nodes with indices (2 * i, 2 * i + 1) and combine their values in their parent with index i. This way when we're asked to find a sum on interval [3, 11), we need to sum up only values in the nodes 19, 5, 12 and 26 (marked with bold), not all 8 values inside the interval. Let's jump directly to implementation (in C++) to see how it works:

As you could notice from the picture, leaves are stored in continuous nodes with indices starting with n, element with index i corresponds to a node with index i + n. So we can read initial values directly into the tree where they belong.

Before doing any queries we need to build the tree, which is quite straightforward and takes O(n) time. Since parent always has index less than its children, we just process all the internal nodes in decreasing order. In case you're confused by bit operations, the code in build() is equivalent to t[i] = t[2*i] + t[2*i+1].

Modifying an element is also quite straightforward and takes time proportional to the height of the tree, which is O(log(n)). We only need to update values in the parents of given node. So we just go up the tree knowing that parent of node p is p / 2 or p>>1, which means the same. p^1 turns 2 * i into 2 * i + 1 and vice versa, so it represents the second child of p's parent.

Finding the sum also works in O(log(n)) time. To better understand it's logic you can go through example with interval [3, 11) and verify that result is composed exactly of values in nodes 19, 26, 12 and 5 (in that order).

General idea is the following. If l, the left interval border, is odd (which is equivalent to l&1) then l is the right child of its parent. Then our interval includes node l but doesn't include it's parent. So we add t[l] and move to the right of l's parent by setting l = (l + 1) / 2. If l is even, it is the left child, and the interval includes its parent as well (unless the right border interferes), so we just move to it by setting l = l / 2. Similar argumentation is applied to the right border. We stop once borders meet.

No recursion and no additional computations like finding the middle of the interval are involved, we just go through all the nodes we need, so this is very efficient.

Arbitrary sized array

For now we talked only about an array with size equal to some power of 2, so the binary tree was perfect. The next fact may be stunning, so prepare yourself.

The code above works for any size n.

Explanation is much more complex than before, so let's focus first on the advantages it gives us.

You can skip the next section and just test the code to check that it's correct. But for those interested in some kind of explanation, here's how the tree for n = 13 looks like: image link

It's not actually a single tree any more, but a set of perfect binary trees: with root 2 and height 4, root 7 and height 2, root 12 and height 2, root 13 and height 1. Nodes denoted by dashes aren't ever used in query operations, so it doesn't matter what's stored there. Leaves seem to appear on different heights, but that can be fixed by cutting the tree before the node 13 and moving its right part to the left. I believe the resulting structure can be shown to be isomorphic to a part of larger perfect binary tree with respect to operations we perform, and this is why we get correct results.

If at some point after modifications we need to inspect all the elements in the array, we can push all the modifications to the leaves using the following code. After that we can just traverse elements starting with index n. This way we reduce the complexity from O(nlog(n)) to O(n) similarly to using build instead of n modifications.

Note, however, that code above works only in case the order of modifications on a single element doesn't affect the result. Assignment, for example, doesn't satisfy this condition. Refer to section about lazy propagation for more information.

Non-commutative combiner functions

For now we considered only the simplest combiner function — addition. It is commutative, which means the order of operands doesn't matter, we have a + b = b + a. The same applies to min and max, so we can just change all occurrences of + to one of those functions and be fine. But don't forget to initialize query result to infinity instead of 0.

However, there are cases when the combiner isn't commutative, for example, in the problem 380C - Sereja and Brackets, tutorial available here http://codeforces.com/blog/entry/10363. Fortunately, our implementation can easily support that. We define structure S and combine function for it. In method build we just change + to this function. In modify we need to ensure the correct ordering of children, knowing that left child has even index. When answering the query, we note that nodes corresponding to the left border are processed from left to right, while the right border moves from right to left. We can express it in the code in the following way:

Lazy propagation

Next we'll describe a technique to perform both range queries and range modifications, which is called lazy propagation. First, we need more variables:

int h = sizeof(int) * 8 - __builtin_clz(n);
int d[N];

h is a height of the tree, the highest significant bit in n. d[i] is a delayed operation to be propagated to the children of node i when necessary (this should become clearer from the examples). Array size if only N because we don't have to store this information for leaves — they don't have any children. This leads us to a total of 3 * n memory use.

Previously we could say that t[i] is a value corresponding to it's segment. Now it's not entirely true — first we need to apply all the delayed operations on the route from node i to the root of the tree (parents of node i). We assume that t[i] already includes d[i], so that route starts not with i but with its direct parent.

Let's get back to our first example with interval [3, 11), but now we want to modify all the elements inside this interval. In order to do that we modify t[i] and d[i] at the nodes 19, 5, 12 and 26. Later if we're asked for a value for example in node 22, we need to propagate modification from node 5 down the tree. Note that our modifications could affect t[i] values up the tree as well: node 19 affects nodes 9, 4, 2 and 1, node 5 affects 2 and 1. Next fact is critical for the complexity of our operations:

Modification on interval [l, r) affects t[i] values only in the parents of border leaves: l+n and r+n-1 (except the values that compose the interval itself — the ones accessed in for loop).

The proof is simple. When processing the left border, the node we modify in our loop is always the right child of its parent. Then all the previous modifications were made in the subtree of the left child of the same parent. Otherwise we would process the parent instead of both its children. This means current direct parent is also a parent of leaf l+n. Similar arguments apply to the right border.

OK, enough words for now, I think it's time to look at concrete examples.

Increment modifications, queries for maximum

This is probably the simplest case. The code below is far from universal and not the most efficient, but it's a good place to start.

Let's analyze it one method at a time. The first three are just helper methods user doesn't really need to know about.

Now that we have 2 variables for every internal node, it's useful to write a method to apply changes to both of them. p < n checks if p is not a leaf. Important property of our operations is that if we increase all the elements in some interval by one value, maximum will increase by the same value.

build is designed to update all the parents of a given node.

push propagates changes from all the parents of a given node down the tree starting from the root. This parents are exactly the prefixes of p in binary notation, that's why we use binary shifts to calculate them.

Now we're ready to look at main methods.

As explained above, we process increment request using our familiar loop and then updating everything else we need by calling build.

To answer the query, we use the same loop as earlier, but before that we need to push all the changes to the nodes we'll be using. Similarly to build, it's enough to push changes from the parents of border leaves.

It's easy to see that all operations above take O(log(n)) time.

Again, this is the simplest case because of two reasons:

order of modifications doesn't affect the result;

when updating a node, we don't need to know the length of interval it represents.

These are just simple O(1) functions to calculate value at node p and to apply a change to the node. But there are two thing to explain:

We suppose there's a value we never use for modification, in our case it's 0. In case there's no such value — we would create additional boolean array and refer to it instead of checking d[p] == 0.

Now we have additional parameter k, which stands for the lenght of the interval corresponding to node p. We will use this name consistently in the code to preserve this meaning. Obviously, it's impossible to calculate the sum without this parameter. We can avoid passing this parameter if we precalculate this value for every node in a separate array or calculate it from the node index on the fly, but I'll show you a way to avoid using extra memory or calculations.

Next we need to update build and push methods. Note that we have two versions of them: one we introduces earlier that processes the whole tree in O(n), and one from the last example that processes just the parents of one leaf in O(log(n)). We can easily combine that functionality into one method and get even more.

Let's explain how they work. First, note that we change our interval to closed by doing r += n-1 in order to calculate parents properly. Since we process our tree level by level, is't easy to maintain current interval level, which is always a power of 2. build goes bottom to top, so we initialize k to 2 (not to 1, because we don't calculate anything for the leaves but start with their direct parents) and double it on each level. push goes top to bottom, so k's initial value depends here on the height of the tree and is divided by 2 on each level.

Main methods don't change much from the last example, but modify has 2 things to notice:

Because the order of modifications is important, we need to make sure there are no old changes on the paths from the root to all the nodes we're going to update. This is done by calling push first as we did in query.

One could notice that we do 3 passed in modify over almost the same nodes: 1 down the tree in push, then 2 up the tree. We can eliminate the last pass and calculate new values only where it's necessary, but the code gets more complicated:

Boolean flags denote if we already performed any changes to the left and to the right. Let's look at an example: image link

We call modify on interval [4, 13):

l = 20, r = 29, we call apply(28);

l = 10, r = 14, we call calc(14) — first node to the right of current interval is exactly the parent of last modified node;

l = 5, r = 7, we call calc(7) and then apply(5) and apply(6);

l = 3, r = 3, so the first loop finishes.

Now you should see the point of doing --l, because we still need to calculate new values in nodes 2, 3 and then 1. End condition is r > 0 because it's possible to get l = 1, r = 1 after the first loop, so we need to update the root, but --l results in l = 0.

True, my implementation is basically a refinement of the one in that post and in Alias's comment to that post. But for some reason it's still not well known and not really searchable, and I wasn't aware of that post. Also I hope to provide more knowledge, especially after I add the section about lazy propagation.

p>>1 equal to p/2, and this give us parent of node. and and p^1 is binary xor operator from discrete math. ^ operato copies the bit if it is set in one operand but not both. and if p is odd p^1 will be even and if p is even p^1 will be odd. this come from binary representation of p. example if 6^1 -> 110 ^ 001 -> 111 -> 7. other expamle : 8^1 -> 1000 ^ 0001 -> 9

Hi, I am new in competitive programming, I was reading this article and trying to use it , but i dont understand how the function query works, for example if I have these numbers 1 47 45 23 348 and I would like the sum from 47 to 23, whats numbers should I put in the arguments???? please help, thanks

I did some speed comparison between recursive and non-recursive lazy segment trees. With array size of 1<<18 and 1e7 randomly chosen operations between modifications and queries. Array size of 1<<18 is of course easier for my recursive code which uses arrays of the size 2^n but on practise it doesn't affect much to the speed of the code.

Probably you're talking about the last example, but the operation there is assignment, not increment. And array looks absolutely correct except it should start with 40 not 33 (I believe 33 is a typo — let me know if it's not the case).

That's the point of 'lazy propagation' — not to modify anything until we really need it. You shouldn't access tree elements directly unless you called push(0, 8).

Is it possible to generalize the structure for the Lazy propagation Loop , as in both the cases the propagation format of the loop changes. In recursion , no matter what the context the function has the same structure for lazy propagation namely , checking the Boolean flag and changing the value of the child nodes..

Can anyone please explain how the code in section "Modification on interval, single element access" actually work with a small example if possiple explaining how to we get sum over a range after the update(which also I am not able to understand!) ?

This example doesn't support getting sum over a range, only single element access (I was hoping it's clear from the heading). It only shows that sometimes we can invert basic operations, but for more complex operations you need lazy propagation.

can you give an example of single element access after some update , i am not able to grasp how query() would return a[p] (as u mentioned in some earlier comment to call query to access an element or simply what does the query() do ?

Thanks for this post, it is very useful for beginners like me. But there is a small problem; the picture of the segment tree at the very beginning of the post is not showing. It would be nice if you fixed that :)

When processing the left border, the node we modify is always the right child of its parent. Then all the previous modifications were made in the subtree of the left child of the same parent. Otherwise we would process the parent instead of both its children. This means current direct parent is also a parent of leaf l+n

I am new to segment tree and algorithms in general. I see a difference in implementation of query function at http://codeforces.com/blog/entry/1256. In my observation query function in this post does not give correct result. Did anyone else notice that?

Great and efficient implementation. Could you please say more about "Modification on interval [l, r) affects t[i] values only in the parents of border leaves: l+n and r+n-1.". Because, the inc method modifies more than the parents of the border leaves.

If I well understood, you want to explain the fact that in query method (max implementation) we need only to push down ONLY to the left border and right border nodes. Since when computing the query we will be using only the nodes along the route. Moreover, this explains the fact that when we finish increment method, we need ONLY to propagate up to to root of the tree starting from the left and right border leaves, so that the tree and the lazy array will be consistent and representing correct values.

Step-by-step, in the simpler case (when n = 2k and we have full binary tree). Consider n = 16:

We have both l and r from [0, 16], as outer world does not know anything about tree representation — it gives is bounds of the query.

First operation of for is executed exactly once before any iteration (as per definition). That is: add n (16 in our case) to both l and r, i.e. convert "array coordinates" to numbers of vertices in the tree.

Then we iterate while current segment is not-empty, that is l < r.

After each iteration we move 'up' the tree. We know that parent of vertex x is , so we should divide both l and r by two. >>= 1 means "bitwise shift by one bit", which works exactly like division by two with rounding down for non-negative integers.

Hi, I am trying to solve SPOJ GSS1 according to this tutorial on Segement Trees. But I am not able to write a query method. Following is my code so far. I understood the logic but not able to write query method. Please help.

I solved some questions based on this method (non-recursive segment trees) and it worked like a charm,but I think this method fails when building of tree depends on position of nodes for calculations, i.e. when there is non-combiner functions. Example: https://www.hackerearth.com/problem/algorithm/2-vs-3/

Sure. Non-recursive bottom-top approach changes order of calculations and node visiting only. If that does not matter (and it does not if there are no complex group operations), you can apply all top-bottom tricks, including dependency on node's position. One way is to get node's interval's borders based on its id, another way is to simple 'embed' all necessary information into node inself, so it not only know value modulo 3, but also its length (or which power of 3 we should use when appending that node to the right).

First thank you for this awesome tutorial.But one thing I was confused about ever since I read the first code was why do you always say : if (r&1) shouldn't it be if ((r^1)&1) ? because if r is odd then we have all of the children of its parent , so we do the changes to its parent rather than r itself.

A wonderful implementation of segment tree . Thanks for this awesome article. If you write another blog or add a section in this blog on persistent segment tree (non-recursive implementation) that will be very helpful.

I tried dividing the array into O(log n) disjoint segment and then DP on them and got AC, but it made me implement a lot more thing, and I think it won't work if the problem asks to print answer for a segment [l; r], for example, GSS1 on SPOJ.

Frankly saying, I didn't watch the whole entry. But anyway I want to coin something.

The reason I use recursive implementation of segment trees besides that it is clear and simple is the fact that it is very generic. Many modifications of it come with no cost. For example it is the matter of additional 5-10 lines to make the tree persistent or to make it work on some huge interval like [0;109]. Your tree is heavily based on binary indexation. So, such modifications should be pretty hard. Am I correct?

True, is't impossible to modify this approach to support persistency or arbitrary intervals. However it handles all other cases better and they are the vast majority. Especially it's noticeable in the simplest (and the most common) case.

Noooo. Very, very, very bad idea. The constant is too large even for Fenwick. Many problems where [0;109] expect participant to compress the data instead of using dynamic structure, so it is usually hard to get accepted even with fair dynamic tree. Using unordered_map instead of it is simply waste of time, in my opinion.

Yes, you are right, data compression of course better. But I guess that perfomance of BIT + unordered_map is not so much worse than performance of dynamic tree. From another hand it's extremely easy way to modify this data structure and it's also possible for some problems.

I'm having difficulty in this problem -->http://www.spoj.com/problems/DQUERY/ the best i could think for a merge step is O(n) which would make my code run in O(n^2 log(n))+O(q*n*log(n)) definitely tle help me in improving my uppper bound;

Is lazy propagation always applicable for a segment tree problem ? Suppose we have to find the lcm of a given range, and there are range update operation of adding a number to the range. Is Lazy propagation applicable here?

Could you please explain the theory behind the first query function? I get how it works but i don't know how to prove it is always correct. I am doing a dissertation on range queries and i am writing about iterative and recursive segment trees, but i have to prove why these functions are correct and i'm struggling right now.

Under "Modification on interval, single element access", in the query function, why we need to sum up the res? We are asked to give the ans 'What is the value at position p?'. We need to reply a single value, why we are summing multiple values in res?

if we build segment tree it will look like this t[1]=6379,t[2]=3117,t[3]=3262,t[4]=2581,t[5]=536,t[6]=1512,t[7]=1750,t[8]=1697,t[9]=884,t[10]=154,t[11]=382,t[12]=574,t[13]=938,t[14]=827,t[15]=923,t[16]=949,t[17]=748,t[18]=806,t[19]=78;

fucntion query(int l, int r) calculate sum of [l,r); it means if you want to calc sum of [5,8] you must call query(5,9). if you want your function calculate interval [l,r] you must implement by this way :

For the sake of breaking language barrier, this bottom-up implementation is called “zkw segment tree” in China, because it was (supposedly) independently discovered by Zhang Kunwei in his famous paper. Not sure who was the earliest inventor though.

Is there a way that we could do better for non-commutative segment trees? For this implementation sometimes node are just not being used, as extra merging were done. (eg: for size 13 in the example shown, we merged 2 and 3 even though it is meaningless)

I just wonder if i could make arbitrary size of array to some nearest power of 2 if i put useless values which don't affect to final result of each query to the rest of indices? For example, making a size of array from 13 to 16, or 29 to 32 and putting -inf for the additional indices in a max-segtree(or 0 in a sum-segtree)

thank you for your reply. But I'm just wondering how people usually implement codes for range operation. For example, fenwick tree with lazy propagation for some situation or non-recursive segment tree(like this article) or recursive segment tree. Which one is the most simple for specific situation? I just heard that it is easier to implement segment tree with lazy propagation with recursive way. So I just wanna know.

So you would go Fenwick Tree whenever you have to do range sum/xor stuff even if you need lazy propagation and would go iterative segtree if there is no need of lazy propagation or complicated stuff in operations except for sum/xor and recursive way for the others, right?

Thanks for yur help. Can you tell how build and push works in sum queries (It says new build and push methods incorporated both types of build and push methods mentioned before). I can't seem to get it. Also why does both calc and apply update t[p]. NO understanding these both methods...

By compacting the code (by author), code longer is simple in understanding although it is simple in implementing....

If we need increment [L..R) range by `value` , need increment only root nodes by `value` * children(i), and d[i] increments by `value`. Other nodes will calculated some later.

For example: if need increment a[4..7] to 5. There only increment t[3] to 5*4, and put d[3] = 5. This apply operation. Other nodes t[6], t[7], t[12], t[13], t[14], t[15] nodes will incremented some later (may never).

I too have encountered the same problem.BRCKTS is the easier version of 380C — Sereja and Brackets but how to modify query function according to the problem as t[p>>1] = t[p] + t[p^1] logic will work for only all problems related with associative operations but here it is not.So I solved this problem by changing the logic to t[p]=combine(t[i << 1], tree[i << 1 | 1]) where p goes from (n+p)/2 to 1 in reverse for loop.Anyone has much more easier modification idea please share.

Actually in 380C — Sereja and Brackets no update type of query is present so no need of modify function is there which will be easy to do with the above mentioned optimized segment tree implementation. Try this BRCKTS using the same modify function as mentioned by Al.Cash you will realize it will not work in that way.

I implemented a generic segment tree based on this article: Code. Usage: simply write two structures struct node and struct node_update representing your tree nodes and updates, then provide function pointers that merge two nodes together, apply an update to a node, and merge two updates.

As a noob I am still confused that what is the requirement of modify() function. As you are just doing the same thing that you did in build() function. Please explain.... But I must say you explained the whole concept in a nice manner..

If n is a power of 2, than you can use the identical code as in the classic recursive Segment Tree.

If n is not a power of 2, it is still possible, but it is definitely harder.

One possible approach: - collect all indices of the segements that partition the query segment (be careful here, the iterative version alternatively finds such segments from the left and right border): there are O(log n) many - then iterate over them from the most left segment to the most right one, until you find the segment that contains the element you want to find. - then continue traversing to either the left or right child until you reach the leave node (this can be done iteratively or recursively).

When you increment the interval by a value, you need to add this value times the interval length to the sum. So, you need to modify the last example where the interval length is maintained, not the one you took.

Hello AI. I was trying to solve this quesetion. I learned that this is a question on Dynamic Segment tree. My question is — Can I implement Dynamic Seg Tree using the approach given. Or should I go for the recursive one?

Thanks for writing!I think this blog very useful for everyone,especially people who want to study about segment tree.Segment tree is a data structure that very amazing and great.This blog give me more knowledge about segment tree

For the first code snippet, why does this not work ? The only thing I changed is I wanted L, R to be inclusive. If R is even which means its the left child meaning it should be added and moved left and iterate over its parents.

Hi Al.cash , after watching few tutorial videos and understanding segment tree, I tried to implement it by understanding your tutorial. I never knew I would be able to implement it so quickly and so efficiently. I can't thank you enough for providing this tutorial. Thankyou so much!!