Interval update of Segment tree

Source: Internet
Author: User

Original address: http://blog.csdn.net/zip_fan/article/details/46775633

Write very well, just began to write the line segment tree yesterday, some places still not very clear, read this blog post, learned the array form to save segment tree, also learned the interval update

The following is the content of the blog post

Distance from the first contact line tree has been more than a year, once again to participate in ACM Summer camp, this is our home to learn younger brother learn younger sisters to explain the line tree, so on their own to re-do the topic read it again, and then write a blog to commemorate a bit. As a rookie, there must be a lot of expression in the text is not very accurate or even wrong place, welcome you to correct me.

As the most popular data structure test center in the algorithm competition in recent years, its usage and questions are endless. As the best data structure to solve the problem of updating and querying the interval, it has the status that other data structures cannot replace. Although the tree array can solve a lot of problems, and the code is low, the space complexity is low, but the limitations are large, such as the problem of interval maximum can not be solved with a tree array.

Then there are two basic uses for the line tree: single-point update and Interval update (also called segment update).

First segment Tree It is a highly balanced two-fork tree, so many binary tree properties it is perfect inheritance, such as with the array to imitate, the parent node subscript *2= the left son's subscript, the parent node subscript *2+1= the right son subscript. And this nature is also in the implementation of line tree has been very good use (of course, there are many different line tree lines, we can study on their own, do not expand here).

So what is a line tree?

Let's look at a question:

HDU1166 Enemy Soldiers

If this problem is done with conventional violence, the soldiers in all camps will be in an array, and then the number of corresponding positions can be updated directly for each operation, adding up from I to J for each query. However, this operation down, for the limit of data 50,000 people, 40,000 commands, obviously will be timed out, then a new data structure segment tree has emerged.

First question: Why is the segment tree fast?

Apparently for M-points n times, the time complexity of the violence is O (m*n). However, the line tree as a binary tree, inherited the good quality of the two fork Tree O (logn), the worst complexity for this problem is O (M*LOGN), this volume is clearly in line with the time requirements.

Second: How is the segment tree handled?

If node x (odd x) records the data of the 1th point, the node x+1 records the data of the 2nd point, then the node X/2 records the valid data on the interval [up], and so on, the topmost parent node records the valid data on the interval [1,n], and for each point the data Data that has and only LOGN nodes is affected by it, so each update uses only the update Logn points, and the query is the same, effectively saving time.

For each node, which represents the value between the interval [x, y], then the left son node represents the value of the [×, (X+y)/2] interval, and the right son node represents the value on the interval [(x+y)/2+1,y], which guarantees no duplication, and ensures that the tree has the shortest number of layers and the highest query efficiency.

Third: The specific implementation of the segment tree?

Then we will follow up on the topic to explain in detail.

inttre[n*4]; voidBuildintNumintLeintRI) {      if(le==RI) {scanf ("%d",&Tre[num]); return ; }      intMid= (Le+ri)/2; Build (Num*2, Le,mid); Build (Num*2+1, mid+1, RI); Tre[num]=tre[num*2]+tre[num*2+1]; }  

The first is the achievement, where num is the subscript, and Le and RI represents the left and right end of the interval, then each layer num*2, the interval is binary, guaranteed the minimum number of layers, while the memory occupies about 4 times times the points, so open the array when open tre[4*n]. The problem is that it needs to be read into each point, and as a binary tree sequence traversal, it's a good guarantee that the first X point is just read into the le=ri=x Tre[num]. The period represented by the Father node contains the interval represented by the child nodes, so the values of the child nodes will affect the parent node, so each time the son node is established, it will pass tre[num]=tre[num*2]+tre[num*2+1]; The operation initializes the Father node, Of course, here is the sum operation so is +, different questions can choose to take the most value and other different operators. Of course, different questions can be based on the requirements of Tre[num] assignment or memset and other methods to build and initialize.

voidUpdateintNumintLeintRiintXinty) {if(le==RI) {Tre[num]+=y; return ; }      intMid= (Le+ri)/2; if(x<=mid) update (NUM*2, Le,mid,x,y); ElseUpdate (Num*2+1, mid+1, Ri,x,y); Tre[num]=tre[num*2]+tre[num*2+1]; }  

Next is the modification operation, inherits the above Num,le,ri, guarantees the consistency, at the same time is doing for the X point to increase the Y person's operation, therefore seeks to x the corresponding Tre[num], then operates, and rolls back. It is important to note, then, that for X to operate, all the tre[num of the interval containing x will need to be modified, so there is the tre[num]=tre[num*2]+tre[num*2+1 before the rollback]; The problem is to increase the decrease (reduce direct-to-X), while others such as taking the maximum minimum, XOR, or value are only used to modify the corresponding operator.

intQueryintNumintLeintRiintXinty) {if(x<=le&&y>=RI) {          returnTre[num]; }      intMid= (Le+ri)/2; intans=0; if(x<=mid) ans+=query (num*2, Le,mid,x,y); if(y>mid) ans+=query (num*2+1, mid+1, Ri,x,y); returnans; }  

The last is the query operation, still inherit the Num,le,ri. And here is the interval query, (in fact, if X=y is a single point query) then if the query interval [x, y] contains the current interval [Le,ri], that is X<=le&&y>=ri, then the tre[num] is already the valid data of this part, so direct return can, otherwise continue to divide the interval query. Similarly, the sum operation according to test instructions can be replaced with XOR, take the maximum value and so on.

The above is the simplest function of segment tree----Single point update.

The following is a bit more difficult for you to bring to the line tree but basically one of the most common uses: Interval updates.

The interval update is a hurdle for beginners, and several steps are relatively difficult to understand. But as long as the mastery, can solve most of the problem of line tree.

First of all, just that question every time is each camp increment and decrement person, then if every time is the Camp X to Camp y each time increases or decreases the person? This way we will find that the single point update operation does not work, no matter how we adjust the effect, and even if every time for X to y each camp to perform a single point of operation, the result seems to be possible, but in the extreme case we update the 1 to n each time, the complexity will reach O (m*n* LOGN), so it will definitely time out, then how to do it? We're going to use the interval update here.

For the interval update, let's take a look at the following question:

Hdu1556color the ball

The problem clearly satisfies all the points that have just been mentioned for each one of them.

So since it is a line tree, first of all, we are still a contribution to initialize, in the achievement stage difference, the reading value of the reading value, the assignment value, the set 0 of the 0, the problem according to need, at the beginning all the balls are not painted, then directly all Tre[num] set to 0, So this time we can not have to write a build alone, direct memset (Tre,0,sizeof (tre));

But the biggest difference from a single-point update is that it has a lazy array!!!!!!!!!! Important place to hit 10 exclamation marks.

Laz, full name lazy, Chinese called lazy tag or delayed update tag.

Because we know that if we update a segment to a node each time, then the number of operations and each point in the interval is exactly the same as the single point update wow! So what do we do? Looking closely at the line tree, you will find a very magical place: Each node represents a value between the interval [Le,ri] and there is a wood!!!!!!!!!! Why do you say it's magical? Update the value of the interval, the value of the interval stored! is a perfect match, every time I update to the corresponding interval I put, I wait for the next need to update the smaller interval, and then two times the value of the update along with the wood there Ah! Can save a lot of time ah, there are wood!

Yes, this is the role of Laz[num]. Below we follow the question again to gradually feel.

First of all, the most the most the most the beginning, is not the update operation, then Laz[num] Natural is all set to 0 (of course, some of the problems have additional initialization requirements, we decide according to the topic).

Then the update operation begins after initialization is complete.

voidUpdateintNumintLeintRiintXinty) {if(x<=le&&y>=RI) {Tre[num]++; Laz[num]++; return ;      } pushdown (num); intMid= (Le+ri)/2; if(x<=mid) update (NUM*2, Le,mid,x,y); if(y>mid) update (NUM*2+1, mid+1, Ri,x,y); }  

This paragraph is for each balloon on the interval [x, y] is painted once, of course, you can also apply the z-color, nothing more than an extra variable to represent the number of paint. Then still the interval to find, until the target range [x, Y] contains the current interval [Le,ri], then the operation on Tre[num] and Laz[num], representing the interval I have so modified, and this interval of the intervals should also be modified, but this time, I save Temporarily do not modify, but I put this modification action exists Laz[num], next time I need to revise.

And when is the next time? is the current interval than I need the target range, I have to use the following value, then forced, can not be lazy, must be modified, at this time, we put up before the lazy Mark Pushdown, so there is a magical pushdown operation.

 void  pushdown (int   num) { if  (Laz[num]!=0   *2 ]+=laz[num]; Tre[num  *2  +1 ]+=laz[num];          Laz[num  *2 ]+=laz[num]; Laz[num  *2  +1 ]+=laz[num];      Laz[num]  =0  ; }  }  

The above is the pushdown operation of this problem. When the laz[num]!=0, that is, the point there is lazy mark, we are going to update, but this question whether to judge Laz[num] has no effect on the whole, but some of the questions again pushdown will affect the whole, For example, when taking the minimum value for a paragraph at the same time as a number, then if not judge 0, will be 0 to the wrong pushdown down, it must be judged laz[num] there is no.

Then Laz[num] should have been modified, so it will be on the two sons of the node of the Tre[num] have an impact, here because is to add, so the use of the + number, other operations according to the specific topic replacement. At the same time, son node of the son node should also be updated, but we are still lazy, take a step forward, so at this time still do not update son node son node, but with the update son node Laz tag to replace.

Back to the previous updata operation, after each modification of the son node Tre[num], under normal circumstances should be the Father node Tre[num] to modify, but this problem Father node Tre[num] will not affect the results behind, so here lazy omitted this step operation, Most of the problems in the actual operation can not be omitted, you must update the value of the son node and then update the Father node in turn.

Finally, the query operation remains.

intQueryintNumintLeintRiintx) {if(le==RI) {          returnTre[num];      } pushdown (num); intMid= (Le+ri)/2; if(x<=mid)returnQuery (num*2, le,mid,x); Else          returnQuery (num*2+1, mid+1, ri,x); }  

With a single point of update when the query is very similar (nonsense, line tree is a comparison template of things), but also added a pushdown operation, the same reason as the update, the last is the default in turn on the Father node update, the reason, no longer repeat.

Here are two basic uses of the segment tree: single-point updating and interval update operations. I believe that if you can carefully read the words, the data structure should also have a certain understanding. and segment tree also has scanning line, interval merge and other advanced usage, and line tree as a data structure, is bound to and other algorithms have chemical reactions, such as Matrix, DP and other operations may be cleverly nested in the line segment tree to form a comprehensive problem, so we go down must do more questions, more sentiment, In order to thoroughly and thoroughly eat this knowledge point.

(go) interval update for segment tree

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.