牛客练习赛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

 

posted on 2020-04-03 19:46  Willems  阅读(158)  评论(0编辑  收藏  举报

导航