ZOJ2011-Dynamic Rankings 树套树?

好久没有写博文了,这题是刚才被 lrj 的题虐了之后写的,这题的题意是告诉你 NN 个数的序列,每次修改一个位置的值,动态查询区间第 kk 个元素

做法是维护一个线段树,这样我们就可以得到区间的信息,但是这时候我们并不能维护区间有序的序列,所以我们要二分答案,查询 llrr 区间内比这个数小的有多少,和 kk 做比较,然后最后得到答案,写起来就是一个线段树和一个平衡树,对于平时写数据结构写多的来说代码量一般,我的代码一向都很长,写了 200 行左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

typedef long long ll;
const int MAX = 50005;
const int oo = 0x3f3f3f3f;

struct Node {
int key, size;
Node* c[2];
} memo[MAX * 20], *cur, *nil;
int a[MAX], n, q;

struct Seg {
int l, r;
Node* root;
} seg[MAX << 2];

inline Node* New(int v) {
cur->key = v;
cur->size = 1;
cur->c[0] = cur->c[1] = nil;
return cur++;
}

inline void rotate(Node*& t, int f) {
Node* k = t->c[f ^ 1];
t->c[f ^ 1] = k->c[f];
k->c[f] = t;
k->size = t->size;
t->size = t->c[0]->size + t->c[1]->size + 1;
t = k;
}

inline void keep(Node*& t, int f) {
if (t == nil)
return;
else if (t->c[f]->c[f]->size > t->c[f ^ 1]->size)
rotate(t, f ^ 1);
else if (t->c[f]->c[f ^ 1]->size > t->c[f ^ 1]->size)
rotate(t->c[f], f), rotate(t, f ^ 1);
else
return;
for (int i = 0; i < 2; i++) keep(t->c[i], i);
for (int i = 0; i < 2; i++) keep(t, i);
}

inline void insert(Node*& t, int v) {
if (t == nil) {
t = New(v);
} else {
t->size++;
insert(t->c[v >= t->key], v);
keep(t, v >= t->key);
}
}

inline Node* del(Node*& t, int v) {
Node* p;
if (t == nil) return nil;
t->size--;
if (v == t->key || t->c[v > t->key] == nil) {
if (t->c[0] != nil && t->c[1] != nil)
p = del(t->c[0], v + 1), t->key = p->key;
else
p = t, t = t->c[t->c[0] == nil];
return p;
} else
return del(t->c[v > t->key], v);
}

inline int getRank(Node* t, int v) {
int ret = 0;
while (t != nil)
if (t->key < v)
ret += t->c[0]->size + 1, t = t->c[1];
else
t = t->c[0];
return ret;
}

inline void init() {
nil = cur = memo;
nil = New(0);
nil->size = 0;
}

inline void init(int k, int l, int r) {
seg[k].l = l;
seg[k].r = r;
seg[k].root = nil;
for (int i = l; i <= r; i++) {
insert(seg[k].root, a[i]);
}
if (l == r) return;
int mid = l + r >> 1;
init(k << 1, l, mid);
init(k << 1 | 1, mid + 1, r);
}

inline void set(int k, int idx, int v) {
del(seg[k].root, a[idx]);
insert(seg[k].root, v);
if (seg[k].l == seg[k].r) return;
int mid = seg[k].l + seg[k].r >> 1;
if (idx <= mid)
set(k << 1, idx, v);
else
set(k << 1 | 1, idx, v);
}

inline int read(int k, int l, int r, int v) {
if (l > r || seg[k].l > r || seg[k].r < l) return 0;
if (seg[k].l >= l && seg[k].r <= r) {
return getRank(seg[k].root, v);
}
return read(k << 1, l, r, v) + read(k << 1 | 1, l, r, v);
}

inline int doit(int lb, int rb, int k) {
int l = -1000000005, r = 1000000005, mid;
int ret;

while (l < r) {
mid = l + r + 1 >> 1;
ret = read(1, lb, rb, mid);
if (ret < k)
l = mid;
else
r = mid - 1;
}

return l;
}

inline void doit() {
char op[5];
int l, r, k;

init();
init(1, 1, n);
while (q--) {
scanf("%s", op);
if (op[0] == 'Q') {
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", doit(l, r, k));
} else {
scanf("%d%d", &l, &r);
set(1, l, r);
a[l] = r;
}
}
}

int main() {
int T;

scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
doit();
}

return 0;
}