BZOJ1573: [Usaco2009 Open]牛绣花cowemb

求半径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\n",ans);
101     return 0;
102 }
View Code

 

posted @ 2017-10-01 17:22  Blue233333  阅读(315)  评论(0编辑  收藏  举报