zoukankan      html  css  js  c++  java
  • 牛客练习赛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
    ", res);
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    Winfroms检测组合键
    深入理解MySQL索引
    Java并发复习笔记
    并发编程三大特性——原子性、可见性、有序性
    redis修改密码
    windows server2016远程桌面设置
    Windows Server 2016离线安装.NET Framework 3.5
    common-io文件io流工具
    树莓派3b配置
    IOT 开源物联网平台
  • 原文地址:https://www.cnblogs.com/Willems/p/12628567.html
Copyright © 2011-2022 走看看