From: Ravenclaw-OIer <44526586+Ravenclaw-OIer@users.noreply.github.com> Date: Sun, 18 Oct 2020 15:25:18 +0000 (+0800) Subject: feat: add CP-style code X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=0f9326e415bc7c4626b5aa5e7fa18362410a39f7;p=oi-wiki%2Fmain.git feat: add CP-style code --- diff --git a/docs/misc/parallel-binsearch.md b/docs/misc/parallel-binsearch.md index c7fda7c5..c7e54e6e 100644 --- a/docs/misc/parallel-binsearch.md +++ b/docs/misc/parallel-binsearch.md @@ -141,6 +141,102 @@ void solve(int l, int r, vector a, vector q) } ``` +下面提供 [【模板】可持久化线段树 2(主席树)](https://www.luogu.com.cn/problem/P3834) 一题使用整体二分的,偏向竞赛风格的写法。 + +???+note "参考代码" + ```cpp + #include + 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 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$ 小。