OSDN Git Service

feat: add CP-style code
authorRavenclaw-OIer <44526586+Ravenclaw-OIer@users.noreply.github.com>
Sun, 18 Oct 2020 15:25:18 +0000 (23:25 +0800)
committerGitHub <noreply@github.com>
Sun, 18 Oct 2020 15:25:18 +0000 (23:25 +0800)
docs/misc/parallel-binsearch.md

index c7fda7c..c7e54e6 100644 (file)
@@ -141,6 +141,102 @@ void solve(int l, int r, vector<Num> a, vector<Query> q)
 }
 ```
 
+下面提供 [【模板】可持久化线段树 2(主席树)](https://www.luogu.com.cn/problem/P3834) 一题使用整体二分的,偏向竞赛风格的写法。
+
+???+note "参考代码"
+    ```cpp
+    #include <bits/stdc++.h>
+    using namespace std;
+    const int N = 200020;
+    const int INF = 1e9;
+    int n, m;
+    int ans[N];
+    // BIT begin
+    int t[N];
+    int a[N];
+    int sum(int p) {
+        int ans = 0;
+        while (p) {
+            ans += t[p];
+            p -= p & (-p);
+        }
+    return ans;
+    }
+    void add(int p, int x) {
+        while (p <= n) {
+            t[p] += x;
+            p += p & (-p);
+        }
+    }
+    // BIT end
+    int tot = 0;
+    struct Query {
+        int l, r, k, id, type;  // set values to -1 when they are not used!
+    } q[N * 2], q1[N * 2], q2[N * 2];
+    void solve(int l, int r, int ql, int qr) {
+        if (ql > qr) return;
+        if (l == r) {
+            for (int i = ql; i <= qr; i++)
+                if (q[i].type == 2) ans[q[i].id] = l;
+            return;
+        }
+        int mid = (l + r) / 2, cnt1 = 0, cnt2 = 0;
+        for (int i = ql; i <= qr; i++) {
+            if (q[i].type == 1) {
+                if (q[i].l <= mid) {
+                    add(q[i].id, 1);
+                    q1[++cnt1] = q[i];
+                } else
+                    q2[++cnt2] = q[i];
+            } else {
+                int x = sum(q[i].r) - sum(q[i].l - 1);
+                if (q[i].k <= x)
+                    q1[++cnt1] = q[i];
+                else {
+                    q[i].k -= x;
+                    q2[++cnt2] = q[i];
+                }
+            }
+        }
+        // rollback changes
+        for (int i = 1; i <= cnt1; i++)
+            if (q1[i].type == 1) add(q1[i].id, -1);
+        // move them to the main array
+        for (int i = 1; i <= cnt1; i++) q[i + ql - 1] = q1[i];
+        for (int i = 1; i <= cnt2; i++) q[i + cnt1 + ql - 1] = q2[i];
+        solve(l, mid, ql, cnt1 + ql - 1);
+        solve(mid + 1, r, cnt1 + ql, qr);
+    }
+    pair<int, int> b[N];
+    int toRaw[N];
+    int main() {
+        scanf("%d%d", &n, &m);
+        // read and discrete input data
+        for (int i = 1; i <= n; i++) {
+            int x;
+            scanf("%d", &x);
+            b[i].first = x;
+            b[i].second = i;
+        }
+        sort(b + 1, b + n + 1);
+        int cnt = 0;
+        for (int i = 1; i <= n; i++) {
+            if (b[i].first != b[i - 1].first) cnt++;
+            a[b[i].second] = cnt;
+            toRaw[cnt] = b[i].first;
+         }
+        for (int i = 1; i <= n; i++) {
+            q[++tot] = {a[i], -1, -1, i, 1};
+        }
+        for (int i = 1; i <= m; i++) {
+            int l, r, k;
+            scanf("%d%d%d", &l, &r, &k);
+            q[++tot] = {l, r, k, i, 2};
+        }
+        solve(0, cnt + 1, 1, tot);
+        for (int i = 1; i <= m; i++) printf("%d\n", toRaw[ans[i]]);
+    }
+    ```
 ### 带修区间第 k 小:整体二分的完整运用
 
 >  **题 4**  [Dynamic Rankings](http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112) 给定一个数列,要支持单点修改,区间查第 $k$ 小。