树套树
外层线段树, 内层平衡树
每次查询的时候需要把区间分解,然后在这些平衡树上二分
注意size域的维护。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200001
#define M 1300001
using namespace std;
int T, n, m;
int a[50001], root[N];
int sz, c[M][2], size[M], val[M], w[M], rnd[M];
void update(int k){
size[k] = size[c[k][0]] + size[c[k][1]] + w[k];
}
void rotate(int &o, int mark){
int cur = c[o][mark];
c[o][mark] = c[cur][mark ^ 1];
c[cur][mark ^ 1] = o;
size[cur] = size[o];
update(o);
o = cur;
}
int Newnode(int num){
int now = ++ sz;
size[now] = w[now] = 1;
c[now][0] = c[now][1] = 0;
rnd[now] = rand();
val[now] = num;
return now;
}
void Insert(int &k, int num){
if(k == 0){
k = Newnode(num);
return;
}
size[k] ++;
if(val[k] == num){
w[k] ++;
return;
}
if(num < val[k]){
Insert(c[k][0], num);
if(rnd[c[k][0]] < rnd[k])
rotate(k, 0);
}
else{
Insert(c[k][1], num);
if(rnd[c[k][1]] < rnd[k])
rotate(k, 1);
}
}
void Delete(int &k, int num){
if(val[k] == num){
if(w[k] > 1){
w[k] --;
size[k] --;
return;
}
if(c[k][0] == 0 || c[k][1] == 0)
k = c[k][0] + c[k][1];
else if(rnd[c[k][0]] < rnd[c[k][1]]){
rotate(k, 0);
Delete(k, num);
}
else{
rotate(k, 1);
Delete(k, num);
}
return;
}
Delete(c[k][num > val[k]], num);
size[k] --;
}
int TMP;
void build(int id, int l, int r, int x, int num){
Insert(root[id], num);
if(l == r)return;
int mid = l + r >> 1;
if(x <= mid)build(id << 1, l, mid, x, num);
else build(id << 1 | 1, mid + 1, r, x, num);
}
void change(int id, int l, int r, int x, int num, int y){
Delete(root[id], y);
Insert(root[id], num);
if(l == r)return;
int mid = l + r >> 1;
if(x <= mid)change(id << 1, l, mid, x, num, y);
else change(id << 1 | 1, mid + 1, r, x, num, y);
}
void find(int id, int num){
if(id == 0)return;
if(val[id] <= num){
TMP += size[c[id][0]] + w[id];
find(c[id][1], num);
}
else find(c[id][0], num);
}
void Qry(int id, int l, int r, int x, int y, int num){
if(l == x && r == y){
find(root[id], num);
return;
}
int mid = l + r >> 1;
if(mid >= y)Qry(id << 1, l, mid, x, y, num);
else if(mid < x)Qry(id << 1 | 1, mid + 1, r, x, y, num);
else{
Qry(id << 1, l, mid, x, mid, num);
Qry(id << 1 | 1, mid + 1, r, mid + 1, y, num);
}
}
int main(){
int test;
int x, y, z;
scanf("%d", &test);
while(test --){
memset(root, 0, sizeof root);
sz = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++)
build(1, 1, n, i, a[i]);
for(int i = 1; i <= m; i ++){
char QAQ = getchar();
for(; QAQ < '!'; QAQ = getchar());
if(QAQ == 'C'){
scanf("%d%d", &x, &y);
change(1, 1, n, x, y, a[x]);
a[x] = y;
}
else{
scanf("%d%d%d", &x, &y, &z);
int l = 0, r = 1000000000;
while(l < r){
int mid = l + r >> 1;
TMP = 0;
Qry(1, 1, n, x, y, mid);
if(TMP >= z)r = mid;
else l = mid + 1;
}
printf("%d\n", r);
}
}
}
}