区间第K大问题,变化包括带修改和不带修改,强制在线和允许离线
修改主要是单点修改,我们前面也只讨论这种情况。
接下来我们从编程复杂度和时空复杂度来讨论几种做法。
1.整体二分(编程复杂度:低-中,时间复杂度:优秀,空间复杂度:优秀)
缺点:只能做离线
优点:空间都是O(n)。常数小。带修改O(nlog2n),不带修改O(nlogn)。
但是不带修改的情况,如果允许的话,个人认为加个树状数组写O(nlog2n)的更好写
这时单次solve中面对的问题是,数列中一些点是1其余都是0,然后求区间和的问题
这个问题把区间和变成前缀和相减,然后用vector来对那些需要求前缀的点做桶排
然后双指针即可做到单次solve为O(k),k为此次处理的操作数,总体O(nlogn)的复杂度
显然如果不差那log的时间,直接用树状数组来处理更好写
下面给了一个带单点修改查询区间第K小的整体二分代码
1 #include <bits/stdc++.h> 2 3 #define lb(x) (x&(-x)) 4 5 using namespace std; 6 7 const int N = 2e5 + 5; 8 9 int t, n, m, k, cnt; 10 11 struct node { 12 int id, i, j, k; 13 }a[N], q1[N], q2[N]; 14 15 int ans[N], b[N]; 16 17 int c[N]; 18 19 char op[5]; 20 21 void add(int i, int x) {while (i <= n) c[i] += x, i += lb(i);} 22 23 int ask(int i) {int res = 0; while (i > 0) res += c[i], i -= lb(i); return res;} 24 25 void solve(int head, int tail, int l, int r) { 26 if (head > tail) return; 27 if (l == r) { 28 for (int i = head; i <= tail; i ++) 29 ans[a[i].id] = r; 30 return; 31 } 32 int mid = l + r >> 1, s1 = 0, s2 = 0; 33 for (int sum, i = head; i <= tail; i ++) 34 if (a[i].id) { 35 sum = ask(a[i].j) - ask(a[i].i - 1); 36 if (sum >= a[i].k) q1[s1 ++] = a[i]; 37 else a[i].k -= sum, q2[s2 ++] = a[i]; 38 } 39 else { 40 if (a[i].j <= mid) q1[s1 ++] = a[i], add(a[i].i, a[i].k); 41 else q2[s2 ++] = a[i]; 42 } 43 for (int i = 0; i < s1; i ++) 44 if (!q1[i].id) 45 add(q1[i].i, -q1[i].k); 46 memcpy(a + head, q1, sizeof(node) * s1); 47 memcpy(a + head + s1, q2, sizeof(node) * s2); 48 solve(head, head + s1 - 1, l, mid); 49 solve(head + s1, tail, mid + 1, r); 50 } 51 52 int main() { 53 ios::sync_with_stdio(false); 54 for (cin >> t; t --; ) { 55 cin >> n >> m; k = cnt = 0; 56 for (int i = 1; i <= n; i ++) { 57 cin >> b[i]; 58 a[++ k] = (node){0, i, b[i], 1}; 59 } 60 for (int l, r, x, i = 1; i <= m; i ++) { 61 cin >> op >> l >> r; 62 if (op[0] == 'Q') { 63 cin >> x; 64 a[++ k] = (node){++ cnt, l, r, x}; 65 } 66 else { 67 a[++ k] = (node){0, l, b[l], -1}; 68 a[++ k] = (node){0, l, b[l] = r, 1}; 69 } 70 } 71 solve(1, k, 1, 1e9); 72 for (int i = 1; i <= cnt; i ++) 73 printf("%d\n", ans[i]); 74 } 75 return 0; 76 }