UVa11607 Cutting Cakes
- 题目链接
- 题意
- 分析
- AC 代码
题目链接
UVa11607 Cutting Cakes
题意
平面上有n(n≤1 500)个点,其中没有3 点共线。另外有m(m≤700 000)条直线,你的任务是对于每条直线,输出3 个数p, q, r,其中p 和q 为该直线两侧的点数(p≤q),r 是直线穿过的点数。
分析
本题限时6s,还是比较宽松的,直接用分块法能通过,比如把 n 个点集分成 8×88\times 88×8 块。
其次,可以构建四叉树求解。先取 mid=n/2mid = n /2mid=n/2 处的点 p,根据其坐标得到划分轴,再遍历所有点 t 进行划分,t 在坐标轴上则存到当前结点数据中,不在坐标轴上则按照其所在象限存入四棵子树的数据中并递归构建子树。此后只需要从根结点递归查询:先求根结点数据的首个点与直线两端点形成的三角形有向面积 s(s>0s > 0s>0 则 ++p;s=0s = 0s=0 则 ++r;s<0s < 0s<0 则 ++q),其它数据点也都求有向面积后进行 p、q、r 进行统计。然后可以利用首个点的有向面积 s 分类讨论四个子结点的计数:s = 0 时,左上象限子结点内的数据全部统计给 p,右下象限子结点内的数据全部统计给 q,然后左下、右上两个象限的子结点进行递归查询;s > 0 时,左上象限子结点内的数据全部统计给 p,然后左下、右下、右上三个象限的子结点进行递归查询;s < 0 时右下象限子结点内的数据全部统计给 q,然后左下、左上、右上三个象限的子结点进行递归查询。
AC 代码
#include <iostream>
#include <algorithm>
using namespace std;#define M 10000
#define N 1510
#define B 8
int x[N], y[N], u[N], v[N], x1, y1, x2, y2, dx1, dy1, dx2, dy2, vx, vy, a, b, m, n, p, r, kase = 0;int cross(int x1, int y1, int x2, int y2) {return x1*y2 - x2*y1;
}struct {int b[N], bx1, by1, bx2, by2, by4, c;void add(int i) {b[c++] = i;if (c == 1) bx1 = bx2 =x[i], by1 = by2 = y[i];else bx1 = min(bx1, x[i]), bx2 = max(bx2, x[i]), by1 = min(by1, y[i]), by2 = max(by2, y[i]);}void query() {int cc = cross(vx, vy, bx1 - x1, by1 - y1); bool e = cc < 0, f = cc == 0, g = cc > 0;cc = cross(vx, vy, bx2 - x1, by1 - y1); e = e || cc < 0; f = f || cc == 0; g = g || cc > 0;cc = cross(vx, vy, bx1 - x1, by2 - y1); e = e || cc < 0; f = f || cc == 0; g = g || cc > 0;cc = cross(vx, vy, bx2 - x1, by2 - y1); e = e || cc < 0; f = f || cc == 0; g = g || cc > 0;if (f || (e && g)) {for (int i=0; i<c; ++i) {cc = cross(vx, vy, x[b[i]]-x1, y[b[i]]-y1);if (cc > 0) ++p;else if (cc == 0) ++r;}} else if (g) p += c;}
} s[B][B];void query() {x1 = (x1 + dx1) % M; y1 = (y1 + dy1) % M; x2 = (x2 + dx2) % M; y2 = (y2 + dy2) % M;if (x1 == x2 && y1 == y2) y2 = (y1 + 1) % M;p = 0; r = 0; vx = x2 - x1; vy = y2 - y1;for (int i=0; i<B; ++i) for (int j=0; j<B; ++j) s[i][j].query();cout << min(p, n-r-p) << ' ' << max(p, n-r-p) << ' ' << r << endl;
}void solve() {cin >> n;for (int i=0; i<n; ++i) cin >> x[i] >> y[i], u[i] = x[i], v[i] = x[i];sort(u, u+n); sort(v, v+n); a = unique(u, u+n) - u; b = unique(v, v+n) - v;for (int i=0; i<B; ++i) for (int j=0; j<B; ++j) s[i][j].c = 0;for (int i=0, j=(a+B-1)/B, k=(b+B-1)/B; i<n; ++i)s[(lower_bound(u, u+a, x[i]) - u) / j][(lower_bound(v, v+b, y[i]) - v) / k].add(i);cout << "Case #" << ++kase << ':' << endl;cin >> m >> x1 >> y1 >> x2 >> y2 >> dx1 >> dy1 >> dx2 >> dy2;while (m--) query();
}int main() {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);int t; cin >> t;while (t--) solve();return 0;
}