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 }