[Reprint] MO team algorithm

Source: Internet
Author: User

From:http://www.cnblogs.com/csoh/p/5904430.html

Problem: There are n number of a sequence, there is m shape such as Ask L, R Inquiry, each query need to answer the number of at least 2 times in the interval.

The simple solution requires reading the number of O (nm). If the data range is small, you can use an array with an O (nm) of time complexity. If you use the STL map to save occurrences, you need the complexity of O (Nmlogn). Is there a quicker way?

Note that the inquiry is not mandatory online, so we can use the offline method. Notice a little, if we have an "intermediate variable" (in this case, the number of occurrences of each number), then [L-1, R], [L + 1, R], [L, R-1], [L, R + 1] can be obtained in the "Basic Operation Time Complexity" (1) of the "intermediate variable". If the appropriate order of inquiry can be arranged so that each query can use the intermediate variables resulting from the last run, then we will be able to complete the inquiry in a better degree of complexity.

(1) If the data is small, use an array, the time complexity is O (1), if the data is large, you can consider discretization or map, time complexity is O (logn).

How do you arrange the inquiry? Here is a very good time complexity method: first, each query as a "point", two points P1, P2 between the distance between ABS (L1-L2) + ABS (R1-R2), that is, the Manhattan distance, and then seek the minimum spanning tree, and then walk along the tree side. Since the distance here is Manhattan distance, such a spanning tree is called the "Manhattan minimum Spanning tree". The smallest Manhattan spanning tree has a dedicated algorithm (2), and the time complexity of surviving into a tree can be only O (MLOGM).

(2) In fact, this is the algorithm of building edges, and still use the traditional prim or Kruskal algorithm to find the minimum spanning tree.

Unfortunately, the minimum spanning tree in Manhattan is very complex and is not recommended in the exam room.

An intuitive approach is to sort by the left endpoint and then by the right endpoint. But the performance is not good. Especially in the face of well-designed data, this method behaves poorly.

For example, there are 6 inquiries as follows: (1, 100), (2, 2), (3, 99), (4, 4), (5, 102), (6, 7).

This data has been sorted by the left endpoint. When handled with the above method, the left endpoint moves 6 times, and the right endpoint moves 98+97+95+98+95=483 times. The right endpoint moves back and forth heavily, seriously affecting the complexity of the time-the order complexity is O (MLOGM), all left end points are moved only to O (n), but the right end of each query moves O (n), a total of M queries, the total number of moves is O (nm), the total number of moves is O (MLOGM + NM There is no reduction in the upper run time.

In fact, we can do a little bit of change in the order of Inquiry Processing: (2, 2), (4, 4), (6, 7), (5, 102), (3, 99), (1, 100).

The left point moves the number of 2+2+1+2+2=9 times, slightly more than the original. The right endpoint is 2+3+95+3+1=104 and the number of moves to the right end is greatly reduced.

The above process inspires us: ① we should not strictly sort by ascending order, but rather flexible sort method according to need; ② if you reduce the number of right end moves appropriately, even a little bit more left endpoint moves, it's also cost-effective in terms of total complexity.

In order to sort, we do not follow the left and right endpoints in a strictly ascending order, but only leave their left and right endpoints in the "probably ascending" state. The specific method is to divide all the intervals into different blocks, and each query is sorted by the block ordinal of the left endpoint, and the left end block is sorted by the right endpoint. Note that this differs from the previous version in that the "first keyword" is the block of the left endpoint, not the left end point.

This is the MO team algorithm. Why is it called the MO team algorithm? This is said to be the Mo Tao (3) of the National training team in 2010, which was mentioned in the assignment.

(3) As Mo Tao often play the captain, we call him Mo team, the algorithm is also known as the MO Team algorithm. (Thank you, the great God, MO team point)

The MO team algorithm first divides the entire sequence into √n blocks (again, just the conceptually divided blocks, in fact we do not need to strictly store blocks), and then sorts each query according to the block ordinal (the same as the right endpoint sort). After that, we start with the first query after the sort and calculate the answer one after the other.

1 intLen//block Length2 3 structquery{4     intL, R, ID, block;5Query () {}//Constructor Overloading6Query (intLintRintID): L (L), R (r), ID (ID) {7block = L/Len;8     }9     BOOL operator< (ConstQuery RHS)Const {Ten         if(block = = Rhs.block)returnR < RHS. R//Not if (L = = rhs. L) return R < RHS. R Return L < RHS. L One         returnBlock < Rhs.block;//Otherwise, this will change back to the algorithm. A     } - }QUERIES[MAXM]; -  themap<int,int>buf; -  -InlinevoidInsertintN) { -     if(Buf.count (n)) +++Buf[n]; -     Else +Buf[n] =1; A } atInlinevoidEraseintN) { -     if(--buf[n] = =0) buf.erase (n); - } -  - intA[MAXN];//Original Sequence -queue<int> ANSS[MAXM];//Storing Answers in  - intMain () { to     intN, M; +CIN >>N; -Len = (int) sqrt (n);//block Length the      for(inti =1; I <= N; i++){ *CIN >>A[i]; $     }Panax NotoginsengCIN >>m; -      for(inti =1; I <= m; i++){ the         intL, R; +CIN >> L >>R; AQueries[i] =Query (L, R, I); the     } +Sort (Queries +1, queries + M +1); -     intL =1, R =1; $buf[a[1]] =1; $      for(inti =1; I <= m; i++){ -queue<int>& ans =Anss[queries[i].id]; -Query &qi =Queries[i]; the          while(R < Qi. R) Insert (a[++R]); -          while(L > Qi. L) Insert (a[--L]);Wuyi          while(R > Qi. R) Erase (a[r--]); the          while(L < Qi. L) Erase (a[l++]); -  Wu          for(map<int,int>::iterator it = Buf.begin (); It! = Buf.end (); ++it) { -             if(It->second >=2){ AboutAns.push (it->First ); $             } -         } -     } -      for(inti =1; I <= m; i++){ Aqueue<int>& ans =Anss[i]; +          while(!Ans.empty ()) { thecout << Ans.front () <<' '; - Ans.pop (); $         } thecout <<Endl; the     } the}

Although we split the block, we can treat all the "ask transfer" equally. The code above has several areas to be aware of.

The first is insert and erase, here before inserting to determine whether the existence, after inserting to determine whether it is 0, but this is not necessary (insert when the new node is initialized to 0,erase to 0 after the processing answer does not affect);

The second is the order of interval change, insert preferably in front, erase best in the back (think about, why);

The third is that the insert always uses the prefix self-increment operator, and erase always uses the suffix operator;

Four is that we have a reference to query before we visit the "Ask for transfer" to reduce the computational amount of runtime addressing;

Five is that we overloaded the constructor of query. Why do you overload it?

We want to automatically calculate block blocks when query gets L, R, ID, and this is accomplished by writing a constructor query (int L, int R, int ID). However, when structs do not have constructors, they are not initialized when instantiated, and constructors are called to initialize them. "Bless him," queries. When an array is established, a constructor is called once for each element. But we only have 3 parameters of the constructor, construction must have 3 parameters. When an array is created without parameters, the compiler will error. The tradeoff is to write a constructor without parameters that avoids the problem.

This sort has a feature. Both L and R are "probably ascending". But l probably like climbing, but the overall rise but there will be a small local decline. R is a bit difficult to describe, it can be seen from many segments of the rapid rise, each rise to the top of the drop to the bottom.

The following is a random generation of 100 data, put the data into the WPS table after the appearance of the chart.

  

There is one more question: Why do we divide the pieces into √n blocks? Let's analyze the complexity of time.

Let's say we divide every k points.

If the current query is in the same block as the left endpoint of the previous query, then the left endpoint is moved to O (k). Although the right endpoint movement may be up to O (n), the sum of the right end points of the whole piece of inquiry is also O (n) (think about it, why). As a result, the whole block is moved to O (k) XO (k) + O (n) with a total of n/k blocks and a time complexity of O (kn + n2/k).

If the query is not in the same block as the previous query left endpoint, then the left endpoint is moved to O (k), but the right endpoint moves up to O (n). Fortunately, this situation is only O (n/k), with a time complexity of O (n + n2/k).

The total number of moves is O (kn + n2/k). Therefore, when K =√n, the upper bound of the operating time is optimal, O (n1.5).

Finally, based on the time complexity of each insert and erase, multiply O (1) or O (Logn) or O (n), the time complexity of the complete algorithm is obtained (the code uses map, O (logn)).

Thank you very much for your great God's guidance Orz this article.

[Reprint] MO team algorithm

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.