区间第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 }
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-27
  • 2021-10-22
  • 2021-08-27
猜你喜欢
  • 2022-12-23
  • 2022-02-28
  • 2022-12-23
  • 2022-01-08
  • 2021-06-03
  • 2021-12-19
  • 2021-08-29
相关资源
相似解决方案