【题目链接】
【思路要点】
- 首先显然的一点是当且仅当两个多边形在 x x x 轴上的跨度不一样,输出 − 1 -1 −1 。
- 考虑一个 x x x 轴上的坐标 i i i ,在满足 x = i x=i x=i 的平面上的任意一点 ( i , y , z ) (i,y,z) (i,y,z) 能够被计入答案当且仅当 ( i , y ) (i,y) (i,y) 在 x − y x-y x−y 轴的投影多边形内, ( i , z ) (i,z) (i,z) 在 x − z x-z x−z 轴的投影多边形内。
- 令直线 x = i x=i x=i 与 x − y x-y x−y 轴的投影多边形的公共部分长度为 f ( i ) f(i) f(i) ,与 x − z x-z x−z 轴的投影多边形的公共部分长度为 g ( i ) g(i) g(i) ,则答案为 ∫ M i n x M a x x f ( x ) ∗ g ( x ) ∗ d x \int_{Minx}^{Maxx}f(x)*g(x)*dx ∫MinxMaxxf(x)∗g(x)∗dx 。
- 将 x x x 轴按照出现过的 x x x 坐标分段,每一段的 f ( x ) , g ( x ) f(x),g(x) f(x),g(x) 均为一次函数,可以方便地求解定积分。
- 时间复杂度 O ( ( N + M ) L o g ( N + M ) ) O((N+M)Log(N+M)) O((N+M)Log(N+M)) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct point {double x, y; }; point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; } point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; } point a[MAXN], b[MAXN], sa[MAXN], sb[MAXN]; int n, m, tot; double p[MAXN]; set <double> st; map <double, int> home; double Int(double l, double r, double a, double b, double c) { double ans = (r - l) * c; ans += (r * r / 2 - l * l / 2) * b; ans += (r * r * r / 3 - l * l * l / 3) * a; return ans; } int main() { int T; read(T); while (T--) { tot = 0; st.clear(); home.clear(); read(n); double Mina = 1e10, Maxa = -1e10; for (int i = 1; i <= n; i++) { read(a[i].x), read(a[i].y); st.insert(a[i].x); chkmin(Mina, a[i].x); chkmax(Maxa, a[i].x); sa[i] = (point) {0, 0}; } a[n + 1] = a[1]; read(m); double Minb = 1e10, Maxb = -1e10; for (int i = 1; i <= m; i++) { read(b[i].x), read(b[i].y); st.insert(b[i].x); chkmin(Minb, b[i].x); chkmax(Maxb, b[i].x); sb[i] = (point) {0, 0}; } if (Minb != Mina || Maxb != Maxa) { puts("-1"); continue; } b[m + 1] = b[1]; for (auto x : st) { p[++tot] = x; home[x] = tot; } for (int i = 1; i <= n; i++) { int l = home[a[i].x], r = home[a[i + 1].x]; double k = (a[i + 1].y - a[i].y) / (a[i + 1].x - a[i].x); if (l < r) sa[l] = sa[l] - (point) {k, a[i].y - k * a[i].x}, sa[r] = sa[r] + (point) {k, a[i].y - k * a[i].x}; else if (l > r) sa[l] = sa[l] - (point) {k, a[i + 1].y - k * a[i + 1].x}, sa[r] = sa[r] + (point) {k, a[i + 1].y - k * a[i + 1].x}; } for (int i = 1; i <= m; i++) { int l = home[b[i].x], r = home[b[i + 1].x]; double k = (b[i + 1].y - b[i].y) / (b[i + 1].x - b[i].x); if (l < r) sb[l] = sb[l] - (point) {k, b[i].y - k * b[i].x}, sb[r] = sb[r] + (point) {k, b[i].y - k * b[i].x}; else if (l > r) sb[l] = sb[l] - (point) {k, b[i + 1].y - k * b[i + 1].x}, sb[r] = sb[r] + (point) {k, b[i + 1].y - k * b[i + 1].x}; } double ans = 0; for (int i = 1; i <= tot - 1; i++) { sa[i] = sa[i - 1] + sa[i]; sb[i] = sb[i - 1] + sb[i]; ans += Int(p[i], p[i + 1], sa[i].x * sb[i].x, sa[i].x * sb[i].y + sa[i].y * sb[i].x, sa[i].y * sb[i].y); } printf("%.10lf\n", ans); } return 0; }