2 条题解
-
3
对于每一次询问,三角形的三个顶点分别为 。一个点 在该三角形内部或边界上,必须同时满足以下三个条件:
- ;
- ;
- ;
令 。我们要求的是满足 的点的数量。
直接统计较为困难,我们采用容斥原理,考虑其对立事件 (即 )和 (即 ):
$\text{Ans} = N(X+Y \le S) - N(X < x \land X+Y \le S) - N(Y < y \land X+Y \le S) + N(X < x \land Y < y \land X+Y \le S)$
观察第四项 :
如果 且 ,那么必然有 。由于题目中 ,因此 。
这意味着只要前两个条件成立,第三个条件 必然成立。
因此,第四项可以直接化简为标准的二维矩形查询 。
最终答案分解为四项简单查询:
- —— 全局一维前缀和。
- —— 按照 坐标扫描线,维护 的树状数组。
- —— 按照 坐标扫描线,维护 的树状数组。
- —— 可以在计算第二项的扫描线中,同步维护一个关于 的树状数组来求得。
#include <cstdio> #include <vector> #include <algorithm> using namespace std; #define N 1000005 #define S 3000005 struct P { int x, y, z; } p[N]; struct Q { int x, y, s, id; } q[N]; struct BIT { int n; vector<int> c; BIT(int n) : n(n), c(n + 1, 0) {} void change(int x, int v) { for (; x <= n; x += x & -x) c[x] += v; } int get(int x) { int res = 0; for (; x > 0; x -= x & -x) res += c[x]; return res; } void clear() { fill(c.begin(), c.end(), 0); } } A(S), B(N); int n, m; int pre[S]; int ans[N]; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d %d", &p[i].x, &p[i].y); p[i].z = p[i].x + p[i].y; pre[p[i].z]++; } // 第一项: 预处理 Z = X + Y 的全局前缀和 for (int i = 1; i < S; i++) { pre[i] += pre[i - 1]; } for (int i = 1, d; i <= m; i++) { scanf("%d %d %d", &q[i].x, &q[i].y, &d); q[i].s = q[i].x + q[i].y + d; q[i].id = i; ans[i] += pre[q[i].s]; // 答案加上第一项 } // 扫描线 1: 求解第二项和第四项 // 按照 X 坐标升序排序 sort(p + 1, p + n + 1, [](const P &a, const P &b) { return a.x < b.x; }); sort(q + 1, q + m + 1, [](const Q &a, const Q &b) { return a.x < b.x; }); for (int x = 0, i = 1, j = 1; x < N; x++) { while (i <= n && p[i].x == x) { A.change(p[i].z, 1); B.change(p[i].y, 1); i++; } while (j <= m && q[j].x - 1 == x) { ans[q[j].id] -= A.get(q[j].s); // 减去第二项 ans[q[j].id] += B.get(q[j].y - 1); // 加上第四项 j++; } } // 扫描线 2: 求解第三项 // 按照 Y 坐标升序排序 sort(p + 1, p + n + 1, [](const P &a, const P &b) { return a.y < b.y; }); sort(q + 1, q + m + 1, [](const Q &a, const Q &b) { return a.y < b.y; }); A.clear(); for (int y = 0, i = 1, j = 1; y < N; y++) { while (i <= n && p[i].y == y) { A.change(p[i].z, 1); i++; } while (j <= m && q[j].y - 1 == y) { int id = q[j].id; ans[id] -= A.get(q[j].s); // 减去第三项 j++; } } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0; }
- 1
信息
- ID
- 2743
- 时间
- 3000ms
- 内存
- 128MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 62
- 已通过
- 8
- 上传者