Gym102361A Angle Beats(直角三角形 计算几何)题解

题意:

(n)个点,(q)个询问,每次问包含询问点的直角三角形有几个

思路:

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 8000 + 10;
typedef long long ll;
const ll mod = 998244353;
typedef unsigned long long ull;
struct Point{
    ll x, y;
    int flag;
}be[maxn], p[maxn];
int Qua(Point a){
    if(a.x > 0 && a.y >= 0) return 1;
    if(a.x <= 0 && a.y > 0) return 2;
    if(a.x < 0 && a.y <= 0) return 3;
    if(a.x >= 0 && a.y < 0) return 4;
}
int cmp1(Point a, Point b) {
	ll d = a.x * b.y - b.x * a.y;
	if(d == 0) {
		return a.x < b.x;
	}
	else{
		return d > 0;
	}
}
bool cmp(const Point &a, const Point &b){
    int qa = Qua(a), qb = Qua(b);
    if(qa == qb){
        return cmp1(a, b);
    }
    return qa < qb;
}
int angle(Point a, Point b){    //爆ll
    ull now = (ull)(a.x - b.x) * (a.x - b.x) + (ull)(a.y - b.y) * (a.y - b.y);
    ull exc = a.x * a.x + a.y * a.y + b.x * b.x + b.y * b.y;
    if(now == exc) return 0;    //直角
    if(now < exc) return -1;    //锐角
    return 1;   //钝角
}
ll cross(Point a, Point b){
    return a.x * b.y - a.y * b.x;
}
ll ans[maxn];
int main(){
	int n, q;
	scanf("%d%d", &n, &q);
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		cnt++;
		scanf("%lld%lld", &be[cnt].x, &be[cnt].y);
		be[cnt].flag = 0;
		p[cnt] = be[cnt];
	}
	for(int i = 1; i <= q; i++){
		cnt++;
		scanf("%lld%lld", &be[cnt].x, &be[cnt].y);
		be[cnt].flag = i;
		p[cnt] = be[cnt];
	}

    for(int i = n + 1; i <= cnt; i++){
        p[0] = be[i];    //直角点
        int tot = 0;
        for(int j = 1; j <= n; j++){
            p[j].x = be[j].x - be[i].x;
            p[j].y = be[j].y - be[i].y;
            p[j].flag = be[j].flag;
        }
        sort(p + 1, p + n + 1, cmp);
        for(int j = 1; j <= n; j++){
            p[j + n] = p[j];
        }

        int R = 2;
        for(int L = 1; L <= n; L++){
            while(R <= 2 * n){
                if(cross(p[L], p[R]) < 0) break;
                if(angle(p[L], p[R]) >= 0) break;
                R++;
            }
            int tR = R;
            while(tR <= 2 * n){
                if(cross(p[L], p[tR]) <= 0) break;
                if(angle(p[L], p[tR]) != 0) break;
                ans[be[i].flag]++;
                tR++;
            }
        }
    }

    for(int i = 1; i <= n; i++){
        p[0] = be[i];   //非直角点
        int tot = 0;
        for(int j = 1; j <= cnt; j++){
            if(j == i) continue;
            tot++;
            p[tot].x = be[j].x - be[i].x;
            p[tot].y = be[j].y - be[i].y;
            p[tot].flag = be[j].flag;
        }
        sort(p + 1, p + tot + 1, cmp);
        for(int j = 1; j <= tot; j++){
            p[j + tot] = p[j];
        }

        int R = 2;
        for(int L = 1; L <= tot; L++){
            while(R <= 2 * tot){
                if(cross(p[L], p[R]) < 0) break;
                if(angle(p[L], p[R]) >= 0) break;
                R++;
            }
            int tR = R;
            while(tR <= 2 * tot){
                if(cross(p[L], p[tR]) <= 0) break;
                if(angle(p[L], p[tR]) != 0) break;
                if(p[L].flag && p[tR].flag == 0){
                    ans[p[L].flag]++;
                }
                else if(p[L].flag == 0 && p[tR].flag){
                    ans[p[tR].flag]++;
                }
                tR++;
            }
        }
    }

    for(int i = 1; i <= q; i++) printf("%lld
", ans[i]);

	return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/11634347.html