【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

 

你可能感兴趣的:(树状数组)