整体二分

学了一下,感觉海星。

说是整体二分,不如就说是分治。

考虑这个问题:Luogu P3834 【模板】可持久化线段树 2

m 次询问,每次询问给出 (l,r,k),问 [l,r] 中第 k 小的值。

一个显然的结论:答案满足单调性,可以二分。

我们首先先简化一下:如果 m=1,怎么维护?

先二分出一个 x,建立树状数组维护 x 的个数,判断其是否小于 k 即可。

那加入 m 次询问怎么办呢?

可以离线下来,运用分治思想将同一范围内的答案统一处理。

具体的,我们定义结构体 (x,y,k,id,opt)。对于询问,x,y,k 表示查询 [x,y] 的第 k 小,此时的 opt=1,对于原数,x 表示原值。

定义操作函数 solve(l,r,L,R) 表示当前处理到 [l,r],值域为 [L,R],对于 L=R,显然,lr 的答案就为 LR)。

  • 对于原数,如果 xmid,那么其在树状数组上的位置就加一。

  • 对于询问,查询 [x,y] 的个数相当于查询原数的值在 [L,mid] 的个数,我们令为 p,如果 pk,那么此时答案在 [L,mid] 中,否则在 [mid+1,R] 中,需要注意,此时的 qik 要减去 p

码风有点抽象,切勿锐评 /qd。

当然你想要正常一点的也可以私信我。

点击查看代码
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 2e5 + 100; int n, m, cnt, mn = 1e18, mx = -1e18, ans[N]; struct Node { int x, y, k, id, opt; } q[N], q1[N], q2[N]; struct Bit { int f[N]; int lowbit(int x) { return x & -x; } void add(int x, int k) { while (x <= n) { f[x] += k; x += lowbit(x); } } int getsum(int x) { int sum = 0; while (x) { sum += f[x]; x -= lowbit(x); } return sum; } } bit; 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].opt) { ans[q[i].id] = L; } } return ; } int mid = (L + R) >> 1, p1 = 0, p2 = 0; for (int i = l; i <= r; i++) { if (!q[i].opt) { if (q[i].x <= mid) { bit.add(q[i].id, 1); q1[++p1] = q[i]; } else { q2[++p2] = q[i]; } } else { int num = bit.getsum(q[i].y) - bit.getsum(q[i].x - 1); if (num >= q[i].k) { q1[++p1] = q[i]; } else { q[i].k -= num; q2[++p2] = q[i]; } } } for (int i = 1; i <= p1; i++) { if (!q1[i].opt) { bit.add(q1[i].id, -1); } } for (int i = 1; i <= p1; i++) { q[i + l - 1] = q1[i]; } for (int i = 1; i <= p2; i++) { q[i + l + p1 - 1] = q2[i]; } solve(l, l + p1 - 1, L, mid), solve(l + p1, r, mid + 1, R); } signed main() { cin >> n >> m; for (int i = 1, x; i <= n; i++) { cin >> x; q[++cnt] = {x, 0, 0, i, 0}; mn = min(mn, x), mx = max(mx, x); } for (int i = 1, l, r, k; i <= m; i++) { cin >> l >> r >> k; q[++cnt] = {l, r, k, i, 1}; } solve(1, cnt, mn, mx); for (int i = 1; i <= m; i++) cout << ans[i] << '\n'; return 0; }

Luogu P2617 Dynamic Rankings

纪念调了一个小时。

和上一题一样,但是要离散化。对于修改记录一下在树状数组上修改相应的值即可。

但是,要注意,这题按上一题的写法不行,因为上一题我的代码中原数记录的是 qix,而询问记录的是 qik,而这题要离散化,所以要统一成为 k

因为这个调了一个小时。

这题的代码和上题差不多。所以你可以提取上一题正常码风的代码。

点击查看代码
#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 100; int n, m, cnt, ans[N], a[N], b[N], tot, in[N]; struct Node { int opt, k, x, y, id; } q[N], q1[N], q2[N]; struct Bit { int f[N]; int lowbit(int x) { return x & -x; } void add(int x, int k) { while (x <= n) { f[x] += k; x += lowbit(x); } } int getsum(int x) { int sum = 0; while (x) { sum += f[x]; x -= lowbit(x); } return sum; } } bit; 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].opt) { ans[q[i].id] = L; } } return ; } int mid = (L + R) >> 1, p1 = 0, p2 = 0; for (int i = l; i <= r; i++) { if (q[i].opt) { if (q[i].k <= mid) { bit.add(q[i].id, q[i].opt); q1[++p1] = q[i]; } else { q2[++p2] = q[i]; } } else { int num = bit.getsum(q[i].y) - bit.getsum(q[i].x - 1); if (num >= q[i].k) { q1[++p1] = q[i]; } else { q[i].k -= num; q2[++p2] = q[i]; } } } for (int i = 1; i <= p1; i++) { if (q1[i].opt) { bit.add(q1[i].id, -q1[i].opt); } } for (int i = 1; i <= p1; i++) { q[i + l - 1] = q1[i]; } for (int i = 1; i <= p2; i++) { q[i + l + p1 - 1] = q2[i]; } solve(l, l + p1 - 1, L, mid); solve(l + p1, r, mid + 1, R); } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; b[++tot] = a[i]; q[++cnt] = {1, a[i], 0, 0, i}; } for (int i = 1; i <= m; i++) { char c; cin >> c; if (c == 'Q') { int l, r, k; cin >> l >> r >> k; q[++cnt] = {0, k, l, r, i}; } else { int l, r; cin >> l >> r; q[++cnt] = {-1, a[l], 0, 0, l}; q[++cnt] = {1, r, 0, 0, l}; b[++tot] = r; a[l] = r; } } sort(b + 1, b + tot + 1); tot = unique(b + 1, b + tot + 1) - b - 1; for (int i = 1; i <= cnt; i++) { if (!q[i].opt) { continue; } int h = lower_bound(b + 1, b + tot + 1, q[i].k) - b; in[h] = q[i].k; q[i].k = h; } solve(1, cnt, 1, tot); for (int i = 1; i <= m; i++) { // cout << ans[i] << ' '; if (ans[i]) { cout << in[ans[i]] << '\n'; } } return 0; }

Luogu P3527 [POI2011] MET-Meteors

这道题不需要离散化,但是要注意区间总长度为 2×m,然后树状数组维护即可。

点击查看代码
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 8e6 + 100; int n, m, cnt, ans[N], t; struct Node { int x, y, k, id; } q[N]; struct Edge { int val, id; } g[N], q1[N], q2[N]; vector<int> G[N]; struct Bit { int f[N]; int lowbit(int x) { return x & -x; } void add(int x, int k) { while (x <= 2 * m) { f[x] += k; x += lowbit(x); } } int getsum(int x) { int sum = 0; while (x) { sum += f[x]; x -= lowbit(x); } return sum; } } bit; int query(int x) { int ans = 0; for (int i = 0; i < G[g[x].id].size(); i++) { ans += bit.getsum(G[g[x].id][i]) + bit.getsum(G[g[x].id][i] + m); if (ans >= g[x].val) { return ans; } } 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++) { ans[g[i].id] = L; } return ; } int mid = (L + R) >> 1, p1 = 0, p2 = 0; for (int i = L; i <= mid; i++) { bit.add(q[i].x, q[i].k); bit.add(q[i].y + 1, -q[i].k); } for (int i = l; i <= r; i++) { int num = query(i); if (num >= g[i].val) { q1[++p1] = g[i]; } else { g[i].val -= num; q2[++p2] = g[i]; } } for (int i = L; i <= mid; i++) { bit.add(q[i].x, -q[i].k); bit.add(q[i].y + 1, q[i].k); } for (int i = 1; i <= p1; i++) { g[i + l - 1] = q1[i]; } for (int i = 1; i <= p2; i++) { g[i + l + p1 - 1] = q2[i]; } solve(l, l + p1 - 1, L, mid); solve(l + p1, r, mid + 1, R); } signed main() { cin >> n >> m; for (int i = 1, x; i <= m; i++) { cin >> x; G[x].push_back(i); } for (int i = 1, x; i <= n; i++) { cin >> x; g[i] = {x, i}; } cin >> t; for (int i = 1, l, r, k; i <= t; i++) { cin >> l >> r >> k; q[i] = {l, r, k, i}; if (r < l) { q[i].y += m; } } t++; q[t] = {1, 2 * m, (int)1e9, t}; solve(1, n, 1, t); for (int i = 1; i <= n; i++) { // cout << ans[i] << ' '; if (ans[i] == t) { cout << "NIE\n"; } else { cout << ans[i] << '\n'; } } return 0; }

__EOF__

本文作者ようこそ!
本文链接https://www.cnblogs.com/ydq1101/p/18346039.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ydq1101  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示