[思路来自已发布的大佬%% 进行了具体的解释]
题目要求交点的个数我们画个图来看一下
那么我们可以发现当我们固定某一点为起点在圆周上进行枚举
两条线有交点的条件是 两条线的端点是插着的
就用上面那个图以圆在X负半轴的交点为起点 黄色和绿色线的端点是插着的 而黄色与红色的没有 所以你就可以发现我刚刚说的是有道理的
所以我们就可以用树状数组(其他你喜欢的也可以)进行维护
之前在通过推道公式求出两个端点的坐标就可以了 (代码中有详细过程)
然后就是化曲为直 我是先将X上下半轴分开 再分别按从小到大和从大到小排
#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<queue> #include<stack> #include<cmath> #define LL long long using namespace std; inline void read(LL &x){ x=0;LL f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar(); } while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); x*=f; } struct node{ double x,y; LL num; }e[100050]; LL n; double a,b,c,d; inline double Y(double X) { return (double)(-a*X-c)*1.0/b; } inline LL cmpy(node a,node b) { return a.y < b.y; } inline LL cmpu(node a,node b) { return a.x>b.x; } inline LL cmpd(node a,node b) { return a.x<b.x; } inline LL lowbite(LL k) { return k&(-k); } LL N; LL tr[100500]; inline void add(LL pos,LL v) { for(LL i=pos;i<=N;i+=lowbite(i)) { tr[i]+=v; } } inline LL query(LL pos) { LL res=0; for(LL i=pos;i>0;i-=lowbite(i)) { res+=tr[i]; } return res; } LL v[50010]; int main() { read(n); scanf("%lf",&d); N=n*2; LL k=0; for(LL TT=1;TT<=n;TT++) { scanf("%lf",&a); scanf("%lf",&b); scanf("%lf",&c); //ax+by+c=0; //x*x+y*y=d*d //y=(-ax-c)/b //x*x+(ax*ax+2*a*c*x+c*c)/b*b = d*d //x*x*b*b + a*a*x*x + 2*a*c*x = d*d*b*b - c*c //(a*a+b*b)*x*x + 2*a*c*x = d*d*b*b - c*c //(a*a+b*b)*x*x + 2*a*c*x +(c*c - d*d*b*b) = 0 if(a==0) { //by+c=0 e[TT*2-1].y = (-c)*1.0/b; e[TT*2-1].x = sqrt(d*d-e[TT*2-1].y); e[TT*2-1].num = TT; e[TT*2].y = (-c)*1.0/b; e[TT*2].num = TT; e[TT*2].x = -sqrt(d*d-e[TT*2].y); if(e[TT*2-1].y < 0) k++; if(e[TT*2].y < 0) k++; continue; } if(b==0) { //ax+c=0 e[TT*2-1].x = (-c)*1.0/a; e[TT*2-1].y = sqrt(d*d-e[TT*2-1].x); e[TT*2-1].num = TT; e[TT*2].x = (-c)*1.0/a; e[TT*2].y = -sqrt(d*d-e[TT*2].x); e[TT*2].num = TT; if(e[TT*2-1].y < 0) k++; if(e[TT*2].y < 0) k++; continue; } LL A=a*a+b*b; LL B=2*a*c; LL C=c*c-d*d*b*b; LL delta=B*B-4*A*C; if(delta<=0) continue; e[TT*2-1].x = (-B+sqrt(delta))*1.0/(2*A); e[TT*2-1].y = Y(e[TT*2-1].x); e[TT*2-1].num = TT; if(e[TT*2-1].y < 0) k++; e[TT*2].x = (-B-sqrt(delta))*1.0/(2*A); e[TT*2].y = Y(e[TT*2].x); e[TT*2].num = TT; if(e[TT*2].y < 0) k++; } stable_sort(e+1,e+1+n*2,cmpy); // for(LL i=1;i<=N;i++) // cout<<e[i].x<<" "<<e[i].y <<" " <<e[i].num<<" Y1Y"<<endl; // cout<<endl; stable_sort(e+1,e+1+k,cmpd); // for(LL i=1;i<=N;i++) // cout<<e[i].x<<" "<<e[i].y <<" " <<e[i].num<<" Y2Y"<<endl; // cout<<endl; stable_sort(e+1+k,e+1+n*2,cmpu); LL ans=0; for(LL i=1;i<=N;i++) { // cout<<e[i].x<<" "<<e[i].y <<" " <<e[i].num<<" YYY"<<endl; if(e[i].num == 0) continue; // cout<<v[e[i].num]<<endl; if(v[e[i].num]==0) { v[e[i].num]=i; add(i,1); } else { // cout<<query(i)<<" "<<query(v[e[i].num])<<endl; LL tmp=(query(i)-query(v[e[i].num])); add(v[e[i].num],-1); // if(tmp<=0) continue; ans+=tmp; } } printf("%lld",ans); return 0; }