cdq分治
CDQ解决三维偏序
为了方便处理时共用一个大概模板
我们都指定 需要被统计的元素作为 归并时 后半部分 也就是说我们指定 需要被统计元素为归并排序(从小到大)中 较大者
首先按第一个属性 sort 可以解开第一种属性的约束关系
再去归并排序第二个属性, 树状数组类似扫描线统计答案

#include <bits/stdc++.h> using namespace std; #define endl "\n" typedef long long ll; const int N = 2e5 + 100; template <typename T> struct BIT { T tr[N]; int n; void init(int n_){ n = n_; for(int i = 0; i <= n; i ++) tr[i] = 0; } int lowbit(int x) {return x & -x;} void add(int x, T v){ for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; } T sum(int x){ T res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } T sum(int l, int r) {return sum(r) - sum(l - 1);} void add(int l, int r, T v) {add(l, v); add(r + 1, -v);}; }; array<int, 5> a[N], t[N]; BIT<int> T; int ans[N]; void cdq(int l, int r) { if (l == r) return; int mid = (l + r) >> 1; cdq(l, mid); cdq(mid + 1, r); int p1 = l, p2 = mid + 1, p3 = 0; while (p1 <= mid || p2 <= r) { if (p2 > r || (p1 <= mid && a[p1][1] <= a[p2][1])) { T.add(a[p1][2], a[p1][3]); t[p3++] = a[p1++]; } else { a[p2][4] += T.sum(a[p2][2]); t[p3++] = a[p2++]; } } for (int i = l; i <= mid; i++) T.add(a[i][2], -a[i][3]); for (int i = 0; i < p3; i++) a[l + i] = t[i]; } void solve() { int n, k; cin >> n >> k; T.init(k + 10); for (int i = 0; i < n; i++) { int x, y, z; cin >> x >> y >> z; a[i] = {x, y, z, 1, 0}; } sort(a, a + n); int p = 0; for (int i = 0; i < n; i++) { if (p != 0 && (a[i][0] == a[p - 1][0] && a[i][1] == a[p - 1][1] && a[i][2] == a[p - 1][2])) { a[p - 1][3]++; } else { a[p++] = a[i]; } } cdq(0, p - 1); for (int i = 0; i < p; i++) ans[a[i][3] + a[i][4] - 1] += a[i][3]; for (int i = 0; i < n; i++) cout << ans[i] << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T = 1; cin >> T; // while (T--) solve(); solve(); return 0; }
这题给出来的样例是错的, 瞪了半天...
我们对时间作为第一个属性排个序, 然后扫描线维护
对于查询操作我们通过二维前缀和转换成四个矩形, 扫描线扫就行

#include <bits/stdc++.h> using namespace std; #define endl "\n"; #define int long long typedef long long ll; const int N = 1e6 + 100; template <typename T> struct BIT { T tr[N]; int n; void init(int n_){ n = n_; for(int i = 0; i <= n; i ++) tr[i] = 0; } int lowbit(int x) {return x & -x;} void add(int x, T v){ for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; } T sum(int x){ T res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } T sum(int l, int r) {return sum(r) - sum(l - 1);} void add(int l, int r, T v) {add(l, v); add(r + 1, -v);}; }; array<int, 4> a[N * 4], t[N * 4]; int ans[N]; BIT<int> T; void cdq(int l, int r) { if (l == r) return; int mid = l + r >> 1; cdq(l, mid); cdq(mid + 1, r); int p1 = l, p2 = mid + 1, p3 = 0; while (p1 <= mid || p2 <= r) { if (p2 > r || (p1 <= mid && a[p1][0] <= a[p2][0])) { if (a[p1][3] == 0) T.add(a[p1][1], a[p1][2]); t[p3++] = a[p1++]; } else { if (a[p2][3] != 0) ans[a[p2][2]] += a[p2][3] * T.sum(a[p2][1]); t[p3++] = a[p2++]; } } for (int i = l; i <= mid; i++) { if (a[i][3] == 0) T.add(a[i][1], -a[i][2]); } for (int i = 0; i < p3; i++) a[l + i] = t[i]; } void solve() { int n; cin >> n; int t = 0, q = 0; T.init(n + 10); while (true) { int op; cin >> op; if (op == 3) break; else if (op == 1) { int x, y, v; cin >> x >> y >> v; a[++t] = {x, y, v, 0}; } else { int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2; q++; a[++t] = {x2, y2, q, 1}; a[++t] = {x1 - 1, y1 - 1, q, 1}; a[++t] = {x2, y1 - 1, q, -1}; a[++t] = {x1 - 1, y2, q, -1}; } } cdq(1, t); for (int i = 1; i <= q; i++) cout << ans[i] << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T; cin >> T; // while (T--) solve(); solve(); return 0; }
先放个代码

#include <bits/stdc++.h> using namespace std; #define endl "\n"; #define int long long typedef long long ll; const int N = 2e5 + 100; template <typename T> struct BIT { T tr[N]; int n; void init(int n_){ n = n_; for(int i = 0; i <= n; i ++) tr[i] = 0; } int lowbit(int x) {return x & -x;} void add(int x, T v){ for(int i = x; i <= n; i += lowbit(i)) tr[i] += v; } T sum(int x){ T res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } T sum(int l, int r) {return sum(r) - sum(l - 1);} void add(int l, int r, T v) {add(l, v); add(r + 1, -v);}; }; int a[N], t[N], pos[N]; BIT<int> T; vector<int> cdq(vector<array<int, 4>> a) { int n = a.size(); vector<int> ans(n + 1, 0); sort(a.begin(), a.end()); vector<array<int, 4>> tmp = a; function<void(int, int)> cdq = [&](int l, int r) { if (l == r) return; int mid = l + r >> 1; cdq(l, mid); cdq(mid + 1, r); int p1 = l, p2 = mid + 1, p3 = 0; while (p1 <= mid || p2 <= r) { if (p2 > r || (p1 <= mid && a[p1][1] <= a[p2][1])) { T.add(a[p1][2], 1); tmp[p3++] = a[p1++]; } else { ans[a[p2][3]] += T.sum(a[p2][2]); tmp[p3++] = a[p2++]; } } for (int i = l; i <= mid; i++) T.add(a[i][2], -1); for (int i = 0; i < p3; i++) a[i + l] = tmp[i]; }; cdq(0, n - 1); // cout << "TEST" << endl; // for (auto i : ans) cout << i << endl; return ans; } void solve() { int n, m; cin >> n >> m; T.init(n + 100); for (int i = 1; i <= n; i++) { cin >> a[i]; pos[a[i]] = i; } for (int i = 1; i <= m; i++) { int x; cin >> x; t[pos[x]] = i; } int cnt = m + 1; for (int i = 1; i <= n; i++) { if (!t[i]) t[i] = cnt++; } vector<array<int, 4>> tmp; for (int i = 1; i <= n; i++) { tmp.push_back({n + 1 - t[i], i, n + 1 - a[i], i}); } vector<int> ans(n + 2, 0); auto ans1 = cdq(tmp); for (int i = 1; i <= n; i++) ans[t[i]] = ans1[i]; tmp.clear(); for (int i = 1; i <= n; i++) { tmp.push_back({n + 1 - t[i], n + 1 - i, a[i], i}); } auto ans2 = cdq(tmp); for (int i = 1; i <= n; i++) ans[t[i]] += ans2[i]; for (int i = n; i >= 1; i--) ans[i] += ans[i + 1]; for (int i = 1; i <= m; i++) cout << ans[i] << endl; } signed main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // int T; cin >> T; // while (T--) solve(); solve(); return 0; }
cdq优化 dp 转移
似乎由于 dp 转移是有一个从左到右的过程那么我们 cdq 分治不能写传统 cdq 分治
得先处理左边,再处理中间,最后处理右边
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效