1 条题解
-
0
题解:Vera and Modern Art
算法思路
本题需要高效处理在无限大平面上的周期性染色和查询。关键在于利用二维差分 + 扫描线 + 树状数组的技巧,将问题转化为一维问题处理。
1. 问题分析
每次染色操作:
- 给定
- 计算 最大的不超过 的 的幂
- 计算 最大的不超过 的 的幂
- 染色点集:,其中
这实际上是在平面上以 为起点, 为 方向周期, 为 方向周期的无限网格染色。
2. 关键转换
坐标变换
将坐标 映射到新的坐标系:
- 的二进制表示逆序后作为新 坐标
- 的二进制表示逆序后作为新 坐标
这样,原来的周期性染色在新坐标系中变成矩形区域染色。
二维差分
对于每个染色操作 在新坐标系中对应的矩形 ,使用二维差分:
3. 算法步骤
- 坐标转换:将原坐标转换为新坐标
- 构建事件:将染色操作转为差分事件,查询操作转为查询事件
- 扫描线:按 坐标排序所有事件
- 树状数组:维护当前 位置对应的 坐标上的值
- 处理查询:遇到查询时在树状数组中查询对应 位置的值
代码实现
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 2e6 + 10, Mxlg = 61; int n, Q; // 二进制逆序 int rev(int Z) { int X = 0, H = 1ll << Mxlg; while (Z) { H >>= 1; if (Z & 1) X |= H; Z >>= 1; } return X; } // 坐标转换:返回新坐标系中的矩形范围 pair<int, int> cov(int x) { int d = __lg(x); // 最高位位置 x ^= (1ll << d); // 去掉最高位 x = rev(x); // 剩余位逆序 return {x + 1, x + (1ll << (Mxlg - d))}; } struct node { int x, y, op, val; // op=1:更新, op=2:查询 }; vector<node> s; int B[N], le, ans[N]; // 离散化映射 int id(int G) { return lower_bound(B + 1, B + 1 + le, G) - B; } // 树状数组 int c[N]; void upd(int pos, int k) { for (int i = pos; i <= le; i += (i & (-i))) c[i] += k; } int qy(int pos) { int res = 0; for (int i = pos; i; i -= (i & (-i))) res += c[i]; return res; } signed main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> n >> Q; // 处理染色操作 for (int i = 1; i <= n; i++) { int x, y, c; cin >> x >> y >> c; auto [lx, rx] = cov(x); auto [ly, ry] = cov(y); // 二维差分 s.push_back({lx, ly, 1, c}); s.push_back({lx, ry, 1, -c}); s.push_back({rx, ly, 1, -c}); s.push_back({rx, ry, 1, c}); B[++le] = rx; B[++le] = ry; } // 处理查询操作 for (int i = 1; i <= Q; i++) { int x, y; cin >> x >> y; s.push_back({rev(x), rev(y), 2, i}); // 查询点转换 B[++le] = rev(y); } // 按x坐标排序 sort(s.begin(), s.end(), [&](node p, node q) { if (p.x != q.x) return p.x < q.x; if (p.y != q.y) return p.y < q.y; return p.op < q.op; }); // 离散化y坐标 sort(B + 1, B + 1 + le); le = unique(B + 1, B + 1 + le) - B - 1; // 扫描线处理 for (auto [x, y, op, v] : s) { if (op == 1) { upd(id(y), v); // 更新树状数组 } else { ans[v] = qy(id(y)); // 查询 } } // 输出答案 for (int i = 1; i <= Q; i++) cout << ans[i] << '\n'; return 0; }关键优化
1. 坐标变换技巧
- 将无限周期性网格映射为有限矩形
- 利用二进制逆序保持空间局部性
2. 二维差分
- 将矩形区域操作转为四个点的操作
- 支持区间修改、单点查询
3. 扫描线 + 树状数组
- 将二维问题降为一维
- 完成每次操作
4. 离散化
- 处理 级别的坐标
- 减少空间开销
复杂度分析
- 时间复杂度:
- 排序:
- 树状数组操作:
- 空间复杂度:
对于 的数据规模,该算法能够高效运行。
算法正确性
- 坐标变换正确性:保证原问题的周期性在新坐标系中变为矩形区域
- 差分正确性:二维差分准确记录区域染色值
- 查询正确性:扫描线过程中树状数组维护当前 位置的所有 坐标值
该算法通过巧妙的坐标变换和数据结构组合,高效解决了大规模周期性染色查询问题。
- 1
信息
- ID
- 4774
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者