牛客练习赛60 F、几何带师 (二维偏序 + 几何基础 + 思维)
作者:互联网
题目:传送门
题意
思路
官方题解
#include <bits/stdc++.h> #define LL long long #define ULL unsigned long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX #define PI acos(-1) #define fir first #define sec second #define lb(x) ((x) & (-(x))) using namespace std; const int N = 1e6 + 5; struct Point { LL x, y; Point(LL x = 0, LL y = 0) : x(x), y(y) { } Point operator + (const Point& A) const { return Point(x + A.x, y + A.y); } Point operator - (const Point& A) const { return Point(x - A.x, y - A.y); } bool operator < (const Point& A) const { return x < A.x || (x == A.x && y < A.y); } bool operator == (const Point& A) const { return x == A.x && y == A.y; } }; LL Dot(Point A, Point B) { return A.x * B.x + A.y * B.y; } LL Cross(Point A, Point B) { return A.x * B.y - A.y * B.x; } double get_dis(Point A, Point B) { return sqrt(Dot(A - B, A - B)); } struct note { LL x, y, add; note(LL x = 0, LL y = 0, LL add = 0) : x(x), y(y), add(add) { } bool operator < (const note& A) const { return x == A.x ? y < A.y : x < A.x; } }E[N]; Point a[N]; int c[N << 1], n; double Ang[N][2], pos[N << 1]; pair < int ,int > id[N]; LL res; void add(int x, int val) { for(int i = x; i <= 200000; i += lb(i)) c[i] += val; } int sum(int x) { int ans = 0; for(int i = x; i > 0; i -= lb(i)) ans += c[i]; return ans; } double get_Ang(double a, double b, double c) { /// 余弦定理算角度 return acos((b * b + c * c - a * a) / (2 * b * c)); } LL solve1(Point A, Point B) { /// 两点在线段AB同边的情况 mem(c, 0); int tot = 0, cnt = 0; LL ans = 0; rep(i, 1, n) { if(Cross(B - A, a[i] - A) > 0) { /// 点 A[i] 在向量AB的左边 tot++; Point P = a[i]; double dispa = get_dis(P, A); double dispb = get_dis(P, B); double disab = get_dis(A, B); Ang[tot][0] = get_Ang(dispb, dispa, disab); Ang[tot][1] = PI - get_Ang(dispa, dispb, disab); pos[++cnt] = Ang[tot][0]; pos[++cnt] = Ang[tot][1]; } } sort(pos + 1, pos + 1 + cnt); rep(i, 1, tot) { id[i].fir = lower_bound(pos + 1, pos + 1 + cnt, Ang[i][0]) - pos; id[i].sec = lower_bound(pos + 1, pos + 1 + cnt, Ang[i][1]) - pos; } sort(id + 1, id + 1 + tot); rep(i, 1, tot) { ans += sum(200000) - sum(id[i].sec); add(id[i].sec, 1); } return ans; } LL solve2(Point A, Point B) {/// 两点在AB的异侧 mem(c, 0); int cnt = 0; LL ans = 0; rep(i, 1, n) { Point P = a[i]; double dispa = get_dis(P, A); double dispb = get_dis(P, B); double disab = get_dis(A, B); Ang[i][0] = get_Ang(dispb, dispa, disab); Ang[i][1] = get_Ang(dispa, dispb, disab); if(Cross(B - A, a[i] - A) > 0) { Ang[i][0] = PI - Ang[i][0]; Ang[i][1] = PI - Ang[i][1]; } pos[++cnt] = Ang[i][0]; pos[++cnt] = Ang[i][1]; } sort(pos + 1, pos + 1 + cnt); rep(i, 1, n) { E[i].x = lower_bound(pos + 1, pos + 1 + cnt, Ang[i][0]) - pos; E[i].y = lower_bound(pos + 1, pos + 1 + cnt, Ang[i][1]) - pos; if(Cross(B - A, a[i] - A) > 0) E[i].add = 0; else E[i].add = 1; } sort(E + 1, E + 1 + n); rep(i, 1, n) { if(E[i].add == 0) ans += sum(E[i].y - 1); if(E[i].add == 1) add(E[i].y, 1); } return ans; } Point A, B; int main() { scanf("%d", &n); scanf("%lld %lld %lld %lld", &A.x, &A.y, &B.x, &B.y); rep(i, 1, n) scanf("%lld %lld", &a[i].x, &a[i].y); res = solve1(A, B) + solve1(B, A) + solve2(A, B); printf("%lld\n", res); return 0; }View Code
标签:偏序,练习赛,return,Point,LL,get,pos,Ang,几何 来源: https://www.cnblogs.com/Willems/p/12628567.html