# Example2 - 动态区间第 $$k$$ 小

## Code

#include <cstdio>
#include <iostream>
using namespace std;
int n, m, sum, cnt, a[200001], c[200001], tmp[400001], Ans[200001];
char opt;
struct node {
int type, x, y, k, tmp, id;
} q[400001], q1[400001], q2[400001];
void add(int k, int x) {
for (int i = k; i <= n; i += i & -i) c[i] += x;
}
int query(int k) {
int ans = 0;
for (int i = k; i > 0; i -= i & -i) ans += c[i];
return ans;
}
void Solve(int L, int R, int l, int r) {
if (L > R) return;  //如果没有东西了就返回
if (l == r) {
for (int i = L; i <= R; i++)
if (q[i].type == 3) Ans[q[i].id] = l;
return;
}  //如果二分到底了就更新答案
int mid = (l + r) >> 1;
for (int i = L; i <= R; i++) {
if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, 1);
if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, -1);
if (q[i].type == 3) tmp[i] = query(q[i].y) - query(q[i].x - 1);
}  //按时间顺序扫一遍加入、删除操作并记录下每个询问内小于当前二分值的数的数量
int len1 = 0, len2 = 0;
for (int i = L; i <= R; i++) {
if (q[i].type == 1 && q[i].y <= mid) add(q[i].x, -1);
if (q[i].type == 2 && q[i].y <= mid) add(q[i].x, 1);  //清空树状数组
if (q[i].type == 3) {
if (q[i].tmp + tmp[i] >
q[i].k -
1)  // q[i].tmp
// 表示的是当前询问在上一个二分值下有多少个小于的数，因为我们丢进当前区间的权值已经不包括之前那些数了
q1[++len1] = q[i];
else {
q[i].tmp += tmp[i];
q2[++len2] = q[i];
}
}  //将询问丢到相应区间
else if (q[i].y <= mid)
q1[++len1] = q[i];
else
q2[++len2] = q[i];  //将权值丢到相应区间
}
for (int i = 1; i <= len1; i++) q[L + i - 1] = q1[i];
for (int i = 1; i <= len2; i++)
q[L + len1 + i - 1] = q2[i];  //重新整理放置操作序列
Solve(L, L + len1 - 1, l, mid);
Solve(L + len1, R, mid + 1, r);  //递归处理
}
int main() {
freopen("2617.in", "r", stdin);
freopen("2617.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum++;
q[sum].type = 1, q[sum].x = i, q[sum].y = a[i];
}  // 第一种操作-加入，存入序列中的值
for (int i = 1; i <= m; i++) {
scanf("%s", &opt);
if (opt == 'Q') {
q[++sum].id = ++cnt;
scanf("%d%d%d", &q[sum].x, &q[sum].y, &q[sum].k);
q[sum].type = 3;
}  //第三种操作-询问，存入询问区间，询问编号，询问值
else {
int A, B;
scanf("%d%d", &A, &B);
sum++;
q[sum].type = 2, q[sum].x = A, q[sum].y = a[A];  //第二种操作，删除
sum++;
q[sum].type = 1, q[sum].x = A, q[sum].y = B;
a[A] = B;
}
}
Solve(1, sum, 0, 2e9);  //整体二分，Start！
for (int i = 1; i <= cnt; i++) printf("%d\n", Ans[i]);
}

posted @ 2019-04-01 21:54  洛水·锦依卫  阅读(209)  评论(0编辑  收藏  举报