Angle Beats Gym - 102361A(计算几何)

Posted jiaaaaaaaqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Angle Beats Gym - 102361A(计算几何)相关的知识,希望对你有一定的参考价值。

Angle Beats

\[ Time Limit: 4000 ms \quad Memory Limit: 1048576 kB \]

题意

给出 \(n\) 个初始点以及 \(q\) 次询问,每次询问给出一个询问点 \(Q\),求包括 \(Q\) 点的直角三角形有多少个。保证 \(n+q\) 个点都不重复。

思路

  1. 对于每次询问,当 \(Q\) 为直角点时,以 \(Q\) 为原点,对 \(n\) 个点做象限极角排序,然后用双指针 \(L\)\(R\) 维护直角三角形的个数。 \(L\) 指针用来枚举其中的一条直角边, \(R\) 指针用来寻找在另一条直角边上的点有多少个,每次找 \(QL\) 这条边逆时针方向的另一条边\(QR\)。所以当 \(L\) 往逆时针转动时,\(R\) 也会往逆时针转动,那么就可以用双指针直接维护出来了,特别注意一下多个点在同一条直线上的情况就可以了。
  2. \(Q\) 不是直角点时,可以离线处理,把 \(n+q\) 个点全部存出来,然后枚举以 \(n\) 个初始点为直角点时,对哪些的 \(Q\) 点有贡献,维护方法同上。

最后的复杂度为 \(O\left(qnC_1 + n(n+q)C_2\right)\)\(C_1、C_2\) 取决于在枚举直角点为原点后,到原点在同一条直线上的点数量。
我试过把 \(n+q\) 个节点全部提取出来,然后暴力枚举每个点为直角点的情况,但是这样复杂度会 \(T\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4+10;

struct Point 
    ll x, y;
    int id;
 p[maxn], be[maxn];
int n, m;
int ans[maxn];

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;
    

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 cmp(Point a, Point b) 
    if(Qua(a) == Qua(b))    return cmp1(a, b);
    else    return Qua(a)<Qua(b);


ll check(Point a, Point b) 
    return a.x*b.x + a.y*b.y;


ll chaji(Point a, Point b) 
    return a.x*b.y - b.x*a.y;


ll work(Point pp) 
    for(int i=1; i<=n; i++) 
        p[i] = be[i];
        p[i].x -= pp.x;
        p[i].y -= pp.y;
    
    p[0] = pp;
    sort(p+1, p+1+n, cmp);
    for(int j=1; j<=n; j++) 
        p[j+n] = p[j];
    
    ll ans = 0;
    int R = 2;
    for(int L=1; L<=n; L++) 
        while(R<=2*n) 
            if(chaji(p[L], p[R]) < 0)   break;
            if(check(p[L], p[R]) <= 0)  break;
            R++;
        
        int tR = R;
        while(tR<=2*n) 
            if(chaji(p[L], p[tR]) <= 0) break;
            if(check(p[L], p[tR]) != 0) break;
            ans++;
            tR++;
        
    
    return ans;


int main()
    // freopen("in", "r", stdin);
    while(~scanf("%d%d", &n, &m)) 
        int all = 0;
        for(int i=1; i<=n; i++) 
            all++;
            int x, y;
            scanf("%d%d", &x, &y);
            p[all].x = x, p[all].y = y, p[all].id = 0;
            be[all] = p[all];
        
        for(int i=1; i<=m; i++) 
            all++;
            int x, y;
            scanf("%d%d", &x, &y);
            p[all].x = x, p[all].y = y, p[all].id = i;
            be[all] = p[all];
            ans[i] = work(p[all]);
        
        for(int i=1; i<=n; i++) 
            for(int j=1; j<=all; j++) 
                p[j] = be[j];
            
            p[0] = be[i];
            int flag = 0;
            for(int j=1; j<=all; j++) 
                if(p[j].x == p[0].x && p[j].y == p[0].y)    flag = 1;
                if(flag)    p[j] = p[j+1];
                p[j].x -= p[0].x;
                p[j].y -= p[0].y;
            

            int nn = all-1;
            sort(p+1, p+1+nn, cmp);
            for(int j=1; j<=nn; j++) 
                p[j+nn] = p[j];
            
            int R = 2;
            for(int L=1; L<=nn; L++) 
                int id = 0;
                if(p[0].id) id = p[0].id;
                if(p[L].id) id = p[L].id;
                while(R<=2*nn) 
                    if(chaji(p[L], p[R]) < 0)   break;
                    if(check(p[L], p[R]) <= 0)  break;
                    R++;
                
                int tR = R;
                while(tR<=2*nn) 
                    if(chaji(p[L], p[tR]) <= 0) break;
                    if(check(p[L], p[tR]) != 0) break;
                    if(id == 0) 
                        if(p[tR].id)    ans[p[tR].id]++;
                     else 
                        if(p[tR].id == 0)   ans[id]++;
                    
                    tR++;
                
            
        
        for(int i=1; i<=m; i++) 
            printf("%d\n", ans[i]);
        
    
    return 0;

以上是关于Angle Beats Gym - 102361A(计算几何)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

GYM102268 Angle Beats(一般图匹配)

CCPC秦皇岛gym102361A. Angle Beats

CCPC秦皇岛gym102361A. Angle Beats

CCPC秦皇岛gym102361A. Angle Beats

Beats Filebeat介绍及使用(十六)