Zoj 2112 Dynamic Rankings (Chair Tree & amp; Dynamic k-level)

Source: Internet
Author: User

Dynamic Rankings Time Limit: 10 Seconds Memory Limit: 32768 KB

The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. they have developed a more powerful system such that for N numbers a [1], a [2],..., a [N], you can ask it like: what is the k-th smallest number of a [I], a [I + 1],..., a [j]? (For some I <= j, 0
Your task is to write a program for this computer, which

-Reads N numbers from the input (1 <= N <= 50,000)

-Processes M instructions of the input (1 <=m <= 10,000 ). these instructions include querying the k-th smallest number of a [I], a [I + 1],..., a [j] and change some a [I] to t.


Input

The first line of the input is a single number X (0 <X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

The first line of each block contains two integers N and M, representing N numbers and M instruction. it is followed by N lines. the (I + 1)-th line represents the number a [I]. then M lines that is in the following format

Q I j k or
C I t

It represents to query the k-th number of a [I], a [I + 1],..., a [j] and change some a [I] to t, respectively. it is guaranteed that at any time of the operation. any number a [I] is a non-negative integer that is less than 1,000,000,000.

There're NO breakline between two continuous test cases.


Output

For each querying operation, output one integer to represent the result. (I. e. the k-th smallest number of a [I], a [I + 1],..., a [j])

There're NO breakline between two continuous test cases.


Sample Input

2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3


Sample Output

3
6
3
6


(Adviser)
Site: Http://zhuzeyuan.hp.infoseek.co.jp/index.files/our_contest_20040619.htm

Author: XIN, Tao

Source:Online Contest of Christopher's Adventure

Question:

A sequence with a length of n (1 <= N <= 50,000) is provided. Each value in the sequence cannot exceed 1e9. Then there are m (1 <= M <= 10,000) operations.

1. Q I j k asks for the k-th value between I and j.

2. C I t: Change the I-th value of the sequence to t.

Ideas:

The Chairman tree is obvious.

There is little information about the Chairman tree on the Internet. So I will introduce the Chairman tree. On the one hand, this helps beginners avoid detours. On the other hand, it is convenient for you to learn. Avoid getting rid of your code after a while...

Let's talk about the concepts related to the Chairman tree.

1. What is the chairman tree.

The Chairman tree seems to be a popular term on the Internet. It seems that the learning name is a functional Line Segment tree. You can use Baidu for related concepts.

2. What is the use of the Chairman tree.

The Chairman tree can solve the k-th big problem in the interval. Of course, this tree can also be completed and the time and space are better than the Chairman tree. What is the use of the Chairman tree. Of course. The Division tree can only solve the big problem of static k. That is to say. If the values in the sequence are updated, the partition tree is no longer applicable. At this time, we will reflect the advantages of the Chairman tree. Other applications of the Chairman tree have not been studied. And then try again.

3. What is the chairman tree.

In fact, the so-called Chairman tree is a bunch of line trees. A bunch of Line Segment trees? A line segment tree consumes so much memory. Isn't a bunch of data starting? This is the essence of the Chairman tree. I will explain it later.

4. How does the Chairman tree solve the k-th Problem in the query interval?

Start with the most basic questions. If the interval is fixed, it is [1, n]. Then ask about the k-th value of the interval. It's easy. Just sort the order, but we want to talk about the line segment tree practice. Considering that the sequence value may be large. We can first hash the n values and map them to the range of 1-n. Then we will insert the n values into the line segment tree. Each node of the Line Segment tree maintains the number of inserted values in the subtree. Then it is easy to find the k-th largest. If k> the number of left subtree values. Find the Nth (k-Number of left subtree values) substring in the right subtree. Otherwise, find it in the right subtree. Recursion continues until it reaches the leaf node. Then, restore the hash value.

Now the key is how to solve the problem that the interval is not [1, n. Suppose we want to query the k Degree of the range [l, r. If we have a line segment tree, R inserts the value in it. Of course it is the same as the method of range [1, n. Suppose we have created n line segment trees. The value of [1, I] is inserted in the I-th tree.I feel that the prefix idea is really clever. It is similar to the character string prefix. The root of the I-th line segment tree is T [I]. So how can we calculate the k size of [l, r. In fact, it is similar to the above method. The key is to know the number of values in the R interval [l, r] of a line segment tree in the left subtree. The number of Subtrees on the right. At this time, the prefix advantage comes. (The number of left subtree values in T [r]-the number of left subtree values in T [L-1]) is not the number of R values in the left subtree. Then, recursively locate the leaf node.

But the problem comes again. So many line segment trees. Even if the memory is not exploding. It's time to make achievements. Here comes the essence. I have to admire the wisdom of my predecessors. The tree structure of the n lines is the same. The number of nodes is the same. This is easy to understand. The number of [1, n] values is maintained. What's even better is. T [I + 1] inserts a value a [I + 1] More than T [I]. imagine if a [I + 1] is inserted with the left subtree of T [I + 1. Then the right subtree of T [I + 1] and the left subtree of T [I] will be exactly the same. Enter the right subtree. Therefore, the right subtree of T [I + 1] does not need to be created. Direct the pointer to the right subtree of T [I + 1] to the right subtree of T [I. Shared node. How witty it is. Solve half of the nodes. This method is recursive. That is, you only need to create the log2 (n) node for T [I + 1. In this way, the k size of static data can be solved.

You can open this question ~

The rest is to solve the major problem of dynamic k. I have understood this place for a long time. To understand. It's actually very easy to understand. If we update arr [I], it will affect T [I] ~ T [n]. Do we need to change them one by one. Obviously, this change is not allowed in time. However, you will find that the change to T [I] ~ T [n] has the same effect. If we increase the influence (the number of values added to the subtree. Number of nodes added to the right subtree. Then we only need to subtract the variable value from the original value. We can use a tree array to record the change value. When we regard changes as a value, it becomes a single point Update Interval summation problem. It's just that it's not a value but a line segment tree, but it can be processed similarly.

That is, the node of each tree array is a line segment tree. Haha. It's really exciting. Then the problem is solved successfully. Analyze the time-space complexity. First, create an empty tree m * log2 (m ). M is the number of hash values. Then create n trees. n * log2 (m ). Then perform the q query operation. 2 * q * log2 (m). Therefore, the total time complexity is. O (m + n + 2 * q) * log2 (m )). Space complexity. 4 * m + n * lon2 (m ).

The following code is attached:

# Include
 
  
# Include
  
   
# Include
   
    
# Include
    
     
# Include
     
      
# Include
      
        # Include
       
         # Include
        
          # Include
         
           # Include
          Using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 60010; const int maxm = 2500010; int ls [maxm], rs [maxm], c [maxm]; // ls, rs, left and right son pointer. The number of c stored values int arr [maxn], H [maxn], T [maxn]; // arr stores the original sequence. H stores the sorted value. T [I] int s [maxn], ua [maxn], ub [maxn], and * use; // s are tree array nodes. Of course, it is also the root of the Line Segment tree. Int n, m, tot; struct node {int l, r, k;} qs [10010]; // hash is required first. Void init () // hash initialization {sort (H, H + m); m = unique (H, H + m)-H;} int Hash (int x) {return lower_bound (H, H + m, x)-H;} int build (int L, int R) // create an empty tree {int rt = tot ++, mid; c [rt] = 0; if (L! = R) {mid = (L + R)> 1; ls [rt] = build (L, mid); rs [rt] = build (mid + 1, r);} return rt;} int Insert (int prt, int x, int val) {int nrt = tot ++, tp = nrt, l = 0, r = m-1, mid; c [nrt] = c [prt] + val; while (l
           
             > 1; if (x <= mid) {ls [nrt] = tot ++, rs [nrt] = rs [prt]; // shared node prt = ls [prt], nrt = ls [nrt]; r = mid;} else {ls [nrt] = ls [prt], rs [nrt] = tot ++; prt = rs [prt], nrt = rs [nrt]; l = mid + 1 ;} c [nrt] = c [prt] + val;} return tp;} int lowbit (int x) {return x & (-x);} void update (int x, int p, int d) // tree array update {while (x <= n) {s [x] = Insert (s [x], p, d ); x + = lowbit (x) ;}} int sum (int x) {int ret = 0; while (x) {ret + = c [ls [use [x]; x-= lowbit (x);} return ret;} int qu (int L, int R, int k) {int lrt = T [L-1], rrt = T [R], l = 0, r = m-1, mid, tp, I, sa, sb; for (I = L-1, use = ua; I-= lowbit (I) use [I] = s [I]; sb = sum (L-1); for (I = R, use = ub; I-= lowbit (I) use [I] = s [I]; sa = sum (R); while (l
            
              > 1; tp = sa-sb + c [ls [rrt]-c [ls [lrt]; // Add and change the value if (k <= tp) {r = mid; lrt = ls [lrt], rrt = ls [rrt]; for (I = L-1, use = ua; I-= lowbit (I )) use [I] = ls [use [I]; // calculate the corresponding subtree change sb = sum (L-1); for (I = R, use = ub; I; i-= lowbit (I) use [I] = ls [use [I]; sa = sum (R);} else {l = mid + 1; k-= tp; lrt = rs [lrt], rrt = rs [rrt]; for (I = L-1, use = ua; I-= lowbit (I )) use [I] = rs [use [I]; sb = sum (L-1); for (I = R, use = ub; I-= lowbit (I )) use [I] = rs [use [I]; sa = sum (R) ;}} return l ;}int main () {int I, q, cas; char op [10]; scanf ("% d", & cas); while (cas --) {scanf ("% d", & n, & q ); tot = m = 0; for (I = 1; I <= n; I ++) scanf ("% d", & arr [I]), H [m ++] = arr [I]; for (I = 0; I
             
              

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.