#include #include #include using namespace std; //快读 int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); } return x * f; } const int N = 300010; int n, m; int a[N]; //维护的序列 int ans[N]; // 结果 struct Node { // op=1 插入, op=-1 删除, op=2 查询 int op; // 插入:l:插入的值,用于二分与mid PK,r:位置 // 删除:l:删除的值,用于二分与mid PK,r:位置 // 查询 [l,r]:查询范围 // k:第k小 int l, r, k; int id; } q[N], lq[N], rq[N]; //树状数组 int tr[N]; void add(int x, int c) { for (; x < n; x += x & -x) tr[x] += c; } //查询x的个数和 int getSum(int x) { int sum = 0; for (; x; x -= x & -x) sum += tr[x]; return sum; } void solve(int l, int r, int ql, int qr) { if (ql > qr) return; //防止RE,递归边界 if (l == r) { //递归到叶子结点,找到答案 for (int i = ql; i <= qr; i++) if (q[i].op == 2) ans[q[i].id] = l; //所有查询请求,标识答案 return; } int mid = (l + r) >> 1; int nl = 0, nr = 0; for (int i = ql; i <= qr; i++) { if (q[i].op < 2) { // 非查询,插入:1 或 删除:-1 if (q[i].l <= mid) //按插入、删除的值与mid相对比进行左右决策 add(q[i].r, q[i].op), lq[++nl] = q[i]; //位置是q[i].r,如果是插入,则+1,如果是删除则-1 else rq[++nr] = q[i]; } else { //查询数组二分 int t = getSum(q[i].r) - getSum(q[i].l - 1); if (q[i].k <= t) lq[++nl] = q[i]; else { q[i].k -= t; rq[++nr] = q[i]; } } } // 有借有还,再借不难 for (int i = ql; i <= qr; i++) if (q[i].op < 2) if (q[i].l <= mid) add(q[i].r, -q[i].op); for (int i = 1; i <= nl; i++) q[ql - 1 + i] = lq[i]; //将左儿子操作数组,拷贝到q中,原来的下标是[0~ql-1],现在无缝接上[ql-1+1~ql-1+nl] for (int i = 1; i <= nr; i++) q[ql - 1 + nl + i] = rq[i]; //将右儿子操作数组,拷贝到q中,原来的下标是[ql-1+nl+i] //继续二分左右儿子 solve(l, mid, ql, ql + nl - 1), solve(mid + 1, r, ql + nl, qr); } int main() { int l, r, k, c = 0, qc = 0; // c:总的操作次数,qc:查询次数 n = read(), m = read(); for (int i = 1; i <= n; i++) a[i] = read(), q[++c] = {1, a[i], i}; // op=1:插入,a[i]:值(用于与mid进行决策左右前进),i:位置 char op[2]; for (int i = 1; i <= m; i++) { scanf("%s", op); if (op[0] == 'Q') { l = read(), r = read(), k = read(); q[++c] = {2, l, r, k, ++qc}; // op=2:查询,[l,r]:区间,k:第k小,++qc:查询的个数 } else { int x = read(), y = read(); //修改操作 q[++c] = {-1, a[x], x}; // op=-1:删除,数值:a[x],位置:x q[++c] = {1, y, x}; // op=1:插入,数值:y,位置:x a[x] = y; //因为a[x]上面有用,所以只能用y临时读入一下,再更新a[x],因为可能存在重复修改,a[x]必须更新 } } //整体二分 solve(-1e9, 1e9, 1, c); //结果 for (int i = 1; i <= qc; i++) printf("%d\n", ans[i]); return 0; }