【ZOJ2112】【整体二分+树状数组】带修改区间第k大

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<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

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

【分析】

裸题,不说了。

按照这种方法的话,离线的带插入修改区间第K大也应该可以做了。

不过这题的经典作法是树状数组上套可持久化线段树,不过这样空间消耗会很大。

可能要用动态开点?

转一个用块状链表的:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/19/3268162.html

  1 /*
  2 宋代晏殊
  3 《蝶恋花·槛菊愁烟兰泣露》
  4 
  5 槛菊愁烟兰泣露。罗幕轻寒,燕子双飞去。明月不谙离恨苦。斜光到晓穿朱户。
  6 昨夜西风凋碧树。独上高楼,望尽天涯路。欲寄彩笺兼尺素。山长水阔知何处。
  7 */
  8 #include <iostream>
  9 #include <cstdio>
 10 #include <algorithm>
 11 #include <cstring>
 12 #include <vector>
 13 #include <utility>
 14 #include <iomanip>
 15 #include <string>
 16 #include <cmath>
 17 #include <queue>
 18 #include <assert.h>
 19 #include <map>
 20 #include <ctime>
 21 #include <cstdlib>
 22 #include <stack>
 23 #define LOCAL
 24 const int INF = 1000000000;
 25 const int MAXN = 300000 + 10;
 26 using namespace std;
 27 struct QUERY{
 28        int x, y;
 29        int k, s, type, cur;//cur用来记录前面的值 
 30 }q[MAXN], q1[MAXN], q2[MAXN];
 31 int Ans[MAXN];
 32 int tmp[MAXN], c[MAXN];
 33 int n, m, num, cnt;
 34 int data[MAXN];
 35 
 36 inline int lowbit(int x){return x&-x;}
 37 void add(int x, int val){
 38      while (x <= n){
 39            c[x] += val;
 40            x += lowbit(x);
 41      }
 42      return;
 43 }
 44 int sum(int x){
 45     int cnt = 0;
 46     while (x > 0){
 47           cnt += c[x];
 48           x -= lowbit(x);
 49     }
 50     return cnt;
 51 }
 52 //整体二分 
 53 void solve(int l, int r, int L, int R){
 54      //这两个都是结束条件
 55      if (l > r) return;
 56      if (L == R){//更新答案
 57         for (int i = l; i <= r; i++)
 58         if (q[i].type == 3) Ans[q[i].s] = L;
 59         return;
 60      }
 61      int mid = (L + R) >> 1;
 62      for (int i = l; i <= r; i++){
 63          if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, 1);
 64          else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, -1);
 65          else if (q[i].type == 3) tmp[i] = sum(q[i].y) - sum(q[i].x - 1);
 66      }
 67      //更新完了就要清除标记了
 68      for (int i = l; i <= r; i++){
 69          if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, -1);
 70          else if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, 1);
 71      }
 72      int l1 = 0, l2 = 0;
 73      for (int i = l; i <= r; i++){
 74          if (q[i].type == 3){
 75             //不用id就直接改 
 76             if (q[i].cur + tmp[i] > q[i].k - 1) q1[++l1] = q[i];
 77             else {
 78                  q[i].cur += tmp[i];
 79                  q2[++l2] = q[i];
 80             }
 81          }else{
 82             if (q[i].y <= mid) q1[++l1] = q[i];
 83             else q2[++l2] = q[i];
 84          }        
 85      }
 86      for (int i = 1; i <= l1; i++) q[i + l - 1] = q1[i];
 87      for (int i = 1; i <= l2; i++) q[i + l1 + l - 1] = q2[i];
 88      solve(l, l + l1 - 1, L, mid);
 89      solve(l + l1, r, mid + 1, R);
 90 }
 91 void init(){
 92      memset(c, 0, sizeof(c));
 93      cnt = num = 0;//指针初始化,num记录总的操作数量 
 94      scanf("%d%d", &n, &m);
 95      for (int i = 1; i <= n; i++){
 96          num++;
 97          scanf("%d", &data[i]);
 98          q[num].x = i;q[num].type = 1;//1代表插入
 99          q[num].s = 0;q[num].y = data[i];//没有用y就当val用 
100      } 
101      for (int i = 1; i <= m; i++){
102          char str[2];
103          num++;
104          scanf("%s", str);
105          if (str[0] == 'Q'){
106             int l, r, k;
107             scanf("%d%d%d", &l, &r, &k);
108             q[num].x = l;q[num].y = r;
109             q[num].type = 3; q[num].s = ++cnt;
110             q[num].k = k;
111          }else{
112             int l, x;
113             scanf("%d%d", &l, &x);
114             q[num].x = l;q[num].y = data[l];//2为删除 
115             q[num].type = 2;q[num].s = 0;
116             q[++num].x = l;
117             q[num].y = x;//删除后插入 
118             q[num].type = 1;
119             q[num].s = 0;
120             data[l] = x;//注意这里一定要改,不然会影响到后面的更新 
121          }
122      }
123      for (int i = 1; i <= num; i++) q[i].cur = 0;
124 }
125 
126 int main(){
127     int T;
128     
129     scanf("%d", &T);
130     while (T--){
131           init();
132           solve(1, num, 0, INF);
133           for (int i = 1; i <= cnt; i++) printf("%d\n", Ans[i]);
134     }
135     return 0;
136 }
View Code

 

posted @ 2015-03-15 15:12  TCtower  阅读(1345)  评论(0编辑  收藏  举报