Angle Beats(计算几何)

Angle Beats

Time Limit: 20000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1435 Accepted Submission(s): 274

Problem Description

Given n points P1, P2, … , Pn on 2D plane and q queries. In i-th query, a point Ai is given, and you should determine the number of tuples (u, v) that 1 ≤ u < v ≤ n and Ai , Pu, Pv form a non-degenerate right-angled triangle.

Input

The first line contains two positive integers n, q (2 ≤ n ≤ 2 000, 1 ≤ q ≤ 2 000), denoting the numberof given points and the number of queries.
Next n lines each contains two integers xi , yi (|xi|, |yi| ≤ 109), denoting a given point Pi.
Next q lines each contains two integers xi , yi (|xi|, |yi| ≤ 109), denoting a query point Ai.
It is guaranteed that the input n + q points are all pairwise distinct.

Output

Output q lines each contains a non-negative integer, denoting the answer to corresponding query.

Sample Input

4 2
0 1
1 0
0 -1
-1 0
0 0
1 1

Sample Output

4
3

Hint

For query (0, 0), the 4 right-angled triangles are
� {(0, 0),(0, 1),(1, 0)}
� {(0, 0),(0, 1),(-1, 0)}
� {(0, 0),(0,-1),(1, 0)}
� {(0, 0),(0,-1),(-1, 0)}
For query (1, 1), the 3 right-angled triangles are
� {(1, 1),(0, 1),(1, 0)}
� {(1, 1),(0, 1),(0,-1)}
� {(1, 1),(1, 0),(-1, 0)}

题意

先给出平面上的n个点 p i p_i pi,然后q次询问,在每次询问时,给出一个坐标 a i a_i ai,求每个 a i a_i ai在p中任选两个点能组成多少直角三角

题解

先想到斜率,然后又从计算几何板子绕回斜率来了。斜率很恶心,我是用pair存的,斜率九成九爆double??我猜的。。。
因为 a i a_i ai是否是直角点会影响我们讨论的边,所以我们分为两种情况分别为 a i a_i ai是直角点和不是直角点

1. a i a_i ai是直角点。此时情况即为
在这里插入图片描述

在这种情况下我们预处理出每个 p j p_j pj a i a_i ai的斜率,用map存下来每个斜率的点的数量
然后枚举 p j p_j pj,显然我们可以将 p j p_j pj旋转到九十度到图中 p k p_k pk的位置,即直线b上的所有点 p p p都满足条件
需要注意的是最后会出现重复加的情况,除2即可。
2. a i a_i ai不是直角点。
在这里插入图片描述
在这种情况下,选择离线处理,然后再对每一个 p j p_j pj预处理出其他点的斜率。
然后枚举 a i a_i ai,依旧是图中直线b上的所有点p都满足,也就是 m a p [ b 的 斜 率 ] map[b的斜率] map[b]

斜率用分数表示,应该没有人不知道分数用pair存,然后取最简分数,特殊的两个用0/1,1/0吧。

代码

// #include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <set>
#include <vector>
#include <assert.h>
#include <cmath>
#include <ctime>
using namespace std;
#define me(x,y) memset((x),(y),sizeof (x))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
// #define int __int128_t

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int maxn = 2200;
const int inf = __INT32_MAX__;
const ll INF = __LONG_LONG_MAX__;
const ll MOD = 998244353;
const double eps = 1e-8;
const double pi = std::acos(-1);
const string cars[] = {"?","?","?"};

struct Point{
    int x,y;
    Point(){}
    Point(double _x,double _y){x = _x,y = _y;}
    bool operator != (Point b)const{return x != b.x || y != b.y;}
    bool operator < (Point b)const{return x == b.x ? y < b.y : x < b.x;}
};

Point p[maxn],a[maxn];
Point po[maxn<<1];
int num[maxn];
map<Point,int> mp;
map<pii,int> e;

pii pa(Point x,Point y){
    pii pa;
    pa.first = x.y - y.y;
    pa.second = x.x - y.x;
    if(pa.first == 0) pa.second = 1;
    else if(pa.second == 0) pa.first = 1;
    else{
        int g = __gcd(pa.first,pa.second);
        pa.first /= g,pa.second /= g;
        if(pa.second < 0) pa.first = -pa.first,pa.second = -pa.second;
    }
    return pa;
}
pii rev(pii x){
    swap(x.first,x.second);
    x.first = -x.first;
    if(x.second < 0) x.first = -x.first,x.second = -x.second;
    if(x.second == 0) x.first = 1;
    return x;
}
int main(){
    ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
    freopen("1in.in","r",stdin);
    freopen("1out.out","w",stdout);
#endif    
    
	int n,q;
    while(cin>>n>>q){
        me(num,0);
        int tot=0;
        for(int i = 1; i <= n; ++i) cin>>p[i].x>>p[i].y;
        for(int i = 1; i <= q; ++i) cin>>a[i].x>>a[i].y;
        for(int i = 1; i <= q; ++i){
            e.clear();
            for(int j = 1; j <= n; ++j) e[pa(p[j],a[i])]++;
            for(int j = 1; j <= n; ++j){
                pii tmp = pa(a[i],p[j]);
                tmp = rev(tmp);
                if(e.count(tmp)) num[i] += e[tmp];
            }
            num[i] /= 2;
        }
        for(int i = 1; i <= n; ++i){
            e.clear();
            for(int j = 1; j <= n; ++j){
                if(i != j) e[pa(p[i],p[j])]++;
            }
            for(int j = 1; j <= q; ++j){
                pii tmp = pa(a[j],p[i]);
                tmp = rev(tmp);
                if(e.count(tmp)) num[j] += e[tmp];
            }
        }
        for(int i = 1; i <= q; ++i) cout<<num[i]<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值