求半径d<=50000的圆(不含边界)内n<=50000条直线有多少交点,给直线的解析式。
一开始就想,如果能求出直线交点与原点距离<d的条件,那么从中不重复地筛选即可。然而两个kx+b联立起来加勾股定理特别丑。。
换个想法,一条线在圆上就截了两个点。把这些点做极角排序后(即从y轴正半轴的射线顺时针扫一圈,把依次遇到的点排下来)后,每条直线就可以两个点表示。设其极角排序后,序较小的那个点叫A,另一个叫B。
其实就是:对所有(Ai,Bi),求有多少j满足Aj<Ai且Ai<Bj<Bi,其中小于号是极角序比较。
这就好比:给若干线段,求有多少对线段相交而不包含。也就是对所有Li,Ri,求有多少Lj<Li并且Li<Rj<Ri。也就是,把原来一条直线看成两个点,两个点按极角序编号,两个点间的弧的交拉直成线段交,求这些线段有多少对交,就变成很裸的扫描线。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 #include<math.h> 6 //#include<iostream> 7 using namespace std; 8 9 int n,d; 10 #define maxn 100011 11 const double eps=1e-10,inf=1e15; 12 struct Line 13 { 14 double k,b; 15 }a[maxn]; 16 struct Point 17 { 18 double x,y,t;int k,id; 19 bool operator < (const Point &b) const 20 {return k<b.k || (k==b.k && t>b.t);} 21 bool operator == (const Point &b) const 22 {return fabs(x-b.x)<eps && fabs(y-b.y)<eps;} 23 bool operator != (const Point &b) const {return !(*this==b);} 24 }p[maxn];int lp=0; 25 double x,y,z; 26 #define LL long long 27 void addp(double x,double y,int id) 28 { 29 Point &e=p[++lp]; 30 e.x=x;e.y=y;e.id=id; 31 e.t=x?y/x:inf; 32 if (x>=0 && y>0) e.k=1; 33 else if (x>0 && y<=0) e.k=2; 34 else if (x<=0 && y<0) e.k=3; 35 else e.k=4; 36 } 37 void makep(int x) 38 { 39 if (a[x].k==inf) 40 { 41 if (a[x].b-d>eps || a[x].b+d<-eps) return; 42 addp(a[x].b,sqrt(1.0*d*d-a[x].b*a[x].b),x); 43 addp(a[x].b,-sqrt(1.0*d*d-a[x].b*a[x].b),x); 44 } 45 else 46 { 47 double u=a[x].k*a[x].k+1,v=2*a[x].k*a[x].b,w=a[x].b*a[x].b-d*d; 48 if (v*v-4*u*w<-eps) return; 49 double tmp=(-v+sqrt(v*v-4*u*w))/(2*u); 50 addp(tmp,a[x].k*tmp+a[x].b,x); 51 tmp=(-v-sqrt(v*v-4*u*w))/(2*u); 52 addp(tmp,a[x].k*tmp+a[x].b,x); 53 } 54 } 55 struct BIT 56 { 57 int a[maxn],n; 58 void clear(int n) {memset(a,0,sizeof(a));this->n=n;} 59 void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;} 60 int query(int x) {int ans=0;for (;x;x-=x&-x) ans+=a[x];return ans;} 61 }t; 62 struct seg 63 { 64 int l,r; 65 bool operator < (const seg &b) const {return l<b.l;} 66 }b[maxn]; 67 bool vis[maxn]; 68 int main() 69 { 70 scanf("%d%d",&n,&d); 71 for (int i=1;i<=n;i++) 72 { 73 scanf("%lf%lf%lf",&x,&y,&z); 74 a[i].k=y?-x/y:inf; 75 a[i].b=y?-z/y:-z/x; 76 makep(i); 77 } 78 sort(p+1,p+1+lp); 79 memset(vis,0,sizeof(vis)); 80 p[lp+1].x=inf;p[lp+1].y=inf; 81 int cnt=0,last=1; 82 for (int i=2;i<=lp+1;i++) if (p[i]!=p[i-1]) 83 { 84 cnt++; 85 for (int &j=last;j<i;j++) 86 if (vis[p[j].id]) b[p[j].id].r=cnt; 87 else vis[p[j].id]=1,b[p[j].id].l=cnt; 88 } 89 for (int i=1;i<=n;i++) if (!vis[i]) b[i].l=b[i].r=0x3f3f3f3f; 90 sort(b+1,b+1+n); 91 LL ans=0;last=1; 92 t.clear(cnt); 93 for (int i=2;i<=(lp>>1)+1;i++) if (b[i].l!=b[i-1].l) 94 { 95 for (int j=last;j<i;j++) 96 ans+=t.query(b[j].r-1)-t.query(b[j].l); 97 for (int &j=last;j<i;j++) 98 t.add(b[j].r,1); 99 } 100 printf("%lld ",ans); 101 return 0; 102 }