2015 北京网络赛 C Protecting Homeless Cats hihoCoder 1229 树状数组

 题意:求在平面上 任意两点连线,原点到这个点的距离小于d的点对有多少个,n=200000;

解: 以原点为圆心做一个半径为d的圆,我们知道圆内的点和园内以外的点的连线都是小于d的还有,圆内和园内的点联线也是小于d的,那么需要处理的是圆外和圆外的点。

以每个圆外的点 向圆做切线 然后我们知道有绿色点区域是允许和他搭配的

那么这些点有一个共同特点 那就他们和圆的切线都在 那个点切点的一侧,这样我们就让每个点 转化为两个切点,然后按照极角排序,求出那些不想交区间就是不合法的

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
const int maxn=200005*2;
const double eps=0.000000000001;
const double PI=acos(-1.0);
struct Point
{
    double x,y;
    Point(double cx=0,double cy=0)
    {
        x=cx; y=cy;
    }
};
struct Circle{
  Point c;
  double r;
  Circle(Point c,double r):c(c),r(r){}
  Point point(double a)
              {
                  return Point(c.x+cos(a)*r,c.y+sin(a)*r);
              }
};
int dcmp(double a)
{
    if(fabs(a)<eps)return 0;
    return a<0?-1:1;
}
double angle(Point v)
{
    return atan2(v.y,v.x);
}
Point operator -(Point A, Point B)
{
    return Point(A.x-B.x,A.y-B.y);
}
double Length(Point c)
{
    return sqrt(c.x*c.x+c.y*c.y);
}
Point Rotate(Point A, double rad)
{
    return Point(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
void getTangents(Point p, Circle C,double &A, double &B)
{
    Point u=p;
    double dist=Length(u);
    if(dcmp(dist-C.r)==0){
      double a=atan2(p.y,p.x);
      if(a<0){
        B=A=a+PI*2;
      }else A=B=a;
   }else{
       double ang=acos(C.r/dist);
       Point t=Rotate(u,ang);
       double a=atan2(t.y,t.x);
       if(a<0)
       {
           A=a+PI*2;
           B=a-ang*2+PI*2;
       }else{
           A=a;
           B=a-ang*2;
           if(B<0)B+=PI*2;
       }
    }
}
Point P[maxn];
struct Elem
{
    double L,R;
    int cL,cR;
    bool operator <(const Elem &rhs)const
    {
        return cL<rhs.cL||(cL==rhs.cL&&cR<rhs.cR);
    }
}E[maxn];
double JJ[maxn*2];
int C[maxn*2];
int lowbit(int x)
{
    return x&(-x);
}
void add(int x,int v,int n)
{
    if(x<=0)return ;
    while(x<=n)
    {
        C[x]+=v;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=C[x];
        x-=lowbit(x);
    }
    return ans;
}
int main()
{
    int n;
    double d;
    while(scanf("%d%lf",&n,&d)==2)
    {
        LL ge=0,nu=0,cc=0;
        Circle c(Point(0,0),d);
        for(int j=0; j<n; j++)
        {
            scanf("%lf%lf",&P[nu].x,&P[nu].y);
            if(dcmp(Length(P[nu])-d)<0)
            {
                ge++;
            }
            else
            {
                getTangents(P[nu],c,E[nu].L,E[nu].R);
                if(E[nu].L>E[nu].R)swap(E[nu].L,E[nu].R);
                JJ[cc++]=E[nu].L;JJ[cc++]=E[nu].R;
                nu++;
            }
        }
        sort(JJ,JJ+cc);
        ge=1;
        for(int i=1; i<cc; i++)
        {
            if(dcmp(JJ[i]-JJ[ge-1])>0)JJ[ge++]=JJ[i];
        }
        cc=ge;
        for(int i=0; i<=cc; i++)C[i]=0;
        for(int i=0; i<nu; i++)
        {
            E[i].cL=upper_bound(JJ,JJ+cc,E[i].L)-JJ;
            E[i].cR=upper_bound(JJ,JJ+cc,E[i].R)-JJ;
            add(E[i].cL,1,cc);
            add(E[i].cR,-1,cc);
        }
        sort(E,E+nu);
        LL buhefa=0;
        for(int i=0; i<nu; i++)
        {
            LL d1= sum(E[i].cR);
            LL d2= sum(E[i].cL-1);
            buhefa+=d1-d2;
            add(E[i].cL,-1,cc);
            add(E[i].cR,1,cc);
        }
        LL nn=n;
        LL ans=nn*(nn-1)/2-buhefa;
        printf("%lld
",ans);
    }
    return 0;
}
/*
4 10
0 2
2 0
0 100
100 0
*/
View Code
 
原文地址:https://www.cnblogs.com/Opaser/p/4938430.html