碰到极角排序不能无脑就用双指针写,要思考是否有更加好的写法
本题由于有三点共线,所以双指针扫描会有问题,由于只要求直角个数,所以我们可以直接用lower_bound二分去找这个就可以
或者也可以用map重载point的=,<,>运算
#include<bits/stdc++.h> using namespace std; #define N 10005 #define db long long const double eps=1e-6; const db pi=acos(-1); int sign(db k){if (k>eps) return 1; else if (k<-eps) return -1; return 0;} int cmp(db k1,db k2){return sign(k1-k2);} struct point{ db x,y; int id; point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} point operator * (db k1) const{return (point){x*k1,y*k1};} point operator / (db k1) const{return (point){x/k1,y/k1};} int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);} point turn90(){return (point){-y,x};} }; db cross(const point &k1,const point &k2){return k1.x*k2.y-k1.y*k2.x;} db dot(point &k1,point &k2){return k1.x*k2.x+k1.y*k2.y;} bool operator <(const point &k1,const point &k2){ if(k1.getP()==k2.getP())return sign(cross(k1,k2))>0; return k1.getP()<k2.getP(); } int n,q,ans[N],tot; point p[N],pp[N],o; int main(){ while(scanf("%d%d",&n,&q)!=EOF){ for(int i=1;i<=n+q;i++){ scanf("%lld%lld",&p[i].x,&p[i].y); p[i].id=0; } for(int i=1;i<=n+q;i++)ans[i]=0; for(int i=1+n;i<=q+n;i++){ o=p[i]; for(int j=1;j<=n;j++)pp[j]=p[j]-o; sort(pp+1,pp+1+n); for(int j=1;j<=n;j++){ point now=pp[j].turn90(); int posl=lower_bound(pp+1,pp+1+n,now)-pp; int posr=upper_bound(pp+1,pp+1+n,now)-pp; ans[i]+=posr-posl; } } for(int i=1;i<=n;i++){ o=p[i]; tot=0; for(int j=1;j<=n;j++)if(j!=i)pp[++tot]=p[j]-o; sort(pp+1,pp+1+tot); for(int j=n+1;j<=n+q;j++){ point now=p[j]-o; now=now.turn90(); int posl=lower_bound(pp+1,pp+1+tot,now)-pp; int posr=upper_bound(pp+1,pp+1+tot,now)-pp; ans[j]+=posr-posl; now=now.turn90(); now=now.turn90(); posl=lower_bound(pp+1,pp+1+tot,now)-pp; posr=upper_bound(pp+1,pp+1+tot,now)-pp; ans[j]+=posr-posl; } } for(int i=1+n;i<=q+n;i++) cout<<ans[i]<<" "; } } /* 4 4 0 0 1 1 1 0 0 1 2 0 0 2 2 1 1 2 */