[Data structure] Line Segment tree

Source: Internet
Author: User

[Data structure] Line Segment tree

 

"Before I introduce other algorithms, let's talk about how you plan to use the line tree to solve this problem ?" Although Xiao Hi is ready to explain, he still hopes to guide Xiao Ho to think step by step, so he said so.

"Well ...... Let me start with the definition of a line segment tree: in fact, the essence of a line segment tree is to use a tree to maintain values related to a certain range and a subinterval, such as the range and the maximum and minimum values of the interval." Mr. Ho said: "The specific method is as follows. The root node of this tree represents the entire range, and the left son node of the root node represents the first half of the range, the right son node of the root node represents the second half of the interval, and so on. For each node of the tree, if the length of the interval indicated by this node is greater than 1, the left son node indicates the First Half of the interval, and the right son indicates the second half of the interval. Taking a section with a length of 10 as an example, we have established a line segment tree like this ."

"The painting works well, but what is the use of such a tree ?" Hi said.

"Let's take the RMQ question as an example. The RMQ question requires solving the minimum value in a range. So I may wish to follow the ST algorithm to solve the minimum value for some intervals that may be used first! If I use a line segment tree to solve this problem, I may as well solve the minimum value in the corresponding interval of each node ." Small Ho-do.

"So I will give you such a set of data, and you will calculate this preprocessing result for me ?" Xiao Hi has another problem.

"Okay! You only have 10 locations, so I will use this tree directly ." When I saw two small Ho brushes, I wrote the minimum value in the interval corresponding to each node on the previously painted Binary Tree: "In fact, this step is quite computation, because the intervals corresponding to each non-leaf node are pieced together by the intervals corresponding to the two son nodes, just like ST, the minimum value in the interval corresponding to such a node is the smaller value in the interval corresponding to the two son nodes. In this way, I only need O (N) time complexity to calculate this tree ."

Little Hi nodded and asked, "I understand, but the interval calculated by a tree is much less than that calculated by the ST algorithm, can you still use Quick Algorithms for queries? What's more, there are changes ?"

Mr. Ho smiled and said, "Let me start with a simple one -- modify. When the weight of a commodity at a certain position changes, that is, the value of a leaf node of this tree has changed-but unlike the ST algorithm, only all the ancestor nodes of this node are included in the interval of this node, in fact, the number of such nodes is very small-only at the O (log (N) level. That is to say, when a modification operation occurs, I only need to change the value of the number of nodes at the O (log (N) level to complete the operation, the time complexity of modification is O (log (N ))."

Hi said, "that's right ~ You pass! But, as I said before, how are you going to use the number range at the O (N) level to handle all the inquiries ?"

Little Ho's smile is still not gone: "This is actually very simple! What I want to do is split a query interval into several intervals that I have calculated (two intervals are split in the ST algorithm ), in this way, if the minimum value calculated for these intervals is the minimum value, I can know the minimum value of the entire interval!"

"How are you going to break down the inquiry interval ?" Asked Hi.

Xiao Ho thought for a moment and said, "This is actually very simple! I start from the root of the Line Segment tree. For the currently accessed line segment Tree node t, set its corresponding range to [A, B]. If the queried range is [l, r] is completely in the first half or the second half-that is, r <= (A + B)/2 or l> (A + B)/2, then recursively enter the subnode corresponding to t for processing (because there is obviously no interval to use in another subtree ). Otherwise, the query interval is divided into two parts: [l, (A + B)/2] and [(A + B)/2 + 1, r]. and enter the left and right subtree of t to process the two query intervals respectively (because the two subtree obviously have intervals to be used )! Of course, if [A, B] overwrites [l, r], you can directly return the minimum value of the previously calculated t sub-tree. In the previous example, if I want to ask about the range [3, 9], my final result will be like this-the range marked in the orange part ."

"First [3, 9] is divided into two intervals: [3, 5] and [6, 9], while [3, 5] is divided into [3, 3] and [4, 5] -- there is no need to continue decomposition. [6, 9] is decomposed into [6, 8] and [9, 9] -- there is no need to continue decomposition. Every step of decomposition is necessary, so this is already the best way to break down ."

Little Hi nodded with satisfaction and said, "does it sound good? But can you guarantee the number of intervals if you break it down like this? What if there are too many ?"

After thinking for a while, Mr. Ho went on to say, "No, except for the first operation to break down two intervals, the number of intervals may double, after each decomposition, the processed interval must have an edge that overlaps with the current node (l = A or r = B), that is, even if the current node is decomposed, there must also be one of the two intervals that need not be decomposed, that is, the total number of intervals is at the depth level, so it is also O (logN."

"It seems that you are quite clear about it. If you want to sum up again, even if you pass the customs, then we can start to explain the following problems ~"

Little Ho said, "Okay! First, I will use the O (N) Time to construct the most primitive line segment tree based on the initial data. In this process, I will use the subnode value to calculate the Father's Day value, this avoids redundant computing. Then, for each operation, if it is a modification, I will update the values of the modified node and all the ancestor nodes of this node. O (logN) can be used) time complexity. If it is a query, I will use the method described above to break down the query interval, although it is not as O (1) as the ST algorithm ), however, it achieves the 'balancer 'mentioned last time. Both the modification and query time complexity are O (logN, so the final time complexity of my algorithm will be O (N + Q * log (N). It is more than enough in this data size!"

"Well ~ O (*  ̄ ▽  ̄ *) o is good ~ So here we are !" Xiao Hi smiled and said, "Hurry up for breakfast !"

Added a detailed explanation of the classic hdu 1166 topic, enemy army deployment (Single Point update)

The sequence of given n numbers, ranging from 1 to n, provides three operations: add p x to increase the number of p x, and sub p x to subtract the number of p from x, query l r, queries the sum of the numbers from l to r (that is, the sum of [l, r ).

 

# Include
 
  
# Include
  
   
# Include
   
    
Using namespace std; const int maxn = 50010; struct SegTree {int l, r; int sum;} segTree [maxn <2]; void Build (int I, int l, int r) {segTree [I]. l = l; segTree [I]. r = r; int mid = (l + r)> 1; if (segTree [I]. l = segTree [I]. r) {scanf (% d, & segTree [I]. sum); return; // do not forget this sentence !!!} Build (I <1, l, mid); Build (I <1) | 1, mid + 1, r); segTree [I]. sum = segTree [I <1]. sum + segTree [(I <1) | 1]. sum;} void Add (int I, int p, int add) {segTree [I]. sum + = add; int l = segTree [I]. l; int r = segTree [I]. r; if (l = r) return; int mid = (l + r)> 1; // Why? Modify a vertex. You only need to modify the vertex and the ancestor nodes that contain the vertex. // we add the nodes starting from the root node. The most important task is to determine which of the left and right children of the root node contains the point to be modified, which only exists in one child, because the two children at the root node represent different intervals. So we can either add value to the left child node or add value to the right child node. How can we judge it? For the root node range [L, R]; // set mid = (L + R) /2; the left child represents [L, mid], and the right child represents [mid + 1, R], which makes it obvious, if the location to be modified is <= mid, we must go to the left // child, because only the left child range includes this point. On the contrary, if we go to the mid, you can only go to the right child. Here is the key, so the added operation starts from the root node and turns down // adds value until the leaf node is found. If (p <= mid) Add (I <1, p, add); else Add (I <1) | 1, p, add );} int Sum (int I, int l, int r) {// Why? This function is the sum of the query interval [l, r], which we call as the target interval; // We Start querying from the root node. // The first consideration is whether to query the root node itself, its left child, or its right child. If l and r are exactly the intervals represented by the root node, then you can directly return the sum value of the root node. // if not, you need to consider the left and right children going, and set the root node range [L, R]. if mid = (L + R)/2, the left child interval is [L, mid], and the right child interval is [mid + 1, R]. how can I find the target range based on the Child range? // If the r of the target range is <= mid, the target range must exist in the left child. If the l> mid of the target range, the target range must exist in the right child. If the mid is between l and r, We need to query the left and right two children. // Note: If a node is queried in the created tree, the interval represented by the node is exactly the parameter of the function, then, you can directly return the sum value of the node. You do not need to query the leaf node down. // if not, you need to query the leaf node, add the sum value of the leaf node // if (segTree [I]. l = segTree [I]. r) // This sentence is a big mistake !!! Be sure to note // return segTree [I]. sum; if (segTree [I]. l = l & segTree [I]. r = r) return segTree [I]. sum; int ans = 0; int mid = (segTree [I]. l + segTree [I]. r)> 1); if (r <= mid) ans = Sum (I <1, l, r); else if (l> mid) ans = Sum (I <1) | 1, l, r); else ans = Sum (I <1, l, mid) + Sum (I <1) | 1, mid + 1, r); return ans;} int main () {char cm [10]; int n; int t; scanf (% d, & t); int p, add, l, r; for (int cas = 1; cas <= t; ++ cas) {printf (Case % d:, cas); scanf (% d, & n); Build (1, 1, n); while (scanf (% s, cm )) {if (cm [0] = 'E') break; if (cm [0] = 'A') {scanf (% d, & p, & add); Add (1, p, add);} else if (cm [0] = 's') {scanf (% d, & p, & add); Add (1, p,-add) ;}else {scanf (% d, & l, & r); printf (% d, Sum (1, l, r) ;}} return 0 ;}
   
  
 


 

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.