bzoj 1573 [Usaco2009 Open]牛绣花cowemb 计算几何 树状数组

先计算几何求每条线在圆上的交点。
然后将两个交点按极角序对应到[l,r]一段区间。那么答案就是求有多少相交区间。按左端点排序离线树状数组扫一遍就行了。

#include <bits/stdc++.h>
using namespace std;
#define N 51000
double d;
int n,top,ans,cnt;
int tr[N<<1];
double st[N<<1];
struct poi
{
    double x,y;
    poi(){}
    poi(double x,double y):x(x),y(y){}
    friend poi operator+(poi p1,poi p2)
    {return poi(p1.x+p2.x,p1.y+p2.y);} 
    friend poi operator-(poi p1,poi p2)
    {return poi(p1.x-p2.x,p1.y-p2.y);}
    friend double operator*(poi p1,poi p2)
    {return p1.x*p2.x+p1.y*p2.y;}
    friend double operator^(poi p1,poi p2)
    {return p1.x*p2.y-p2.x*p1.y;}
    friend poi operator*(double k,poi p1)
    {return poi(p1.x*k,p1.y*k);}
    friend bool operator < (const poi &p1,const poi &p2)
    {return p1.x<p2.x;}
    double dis(){return x*x+y*y;}
    double alp(){return atan2(y,x);}
    void print(){printf("%lf %lf\n",x,y);}
}p[N];
struct line
{
    poi p,v;
    line(){}
    line(poi p,poi v):p(p),v(v){}
}l[N],l1;
poi intersect(line l1,line l2)
{
    poi u=l1.p-l2.p;
    double tmp=(u^l2.v)/(l2.v^l1.v);
    return l1.p+tmp*l1.v;
}
poi move(poi p1,poi dir,double dis)
{return p1+(dis/sqrt(dir.dis()))*dir;}
int get(double x){return lower_bound(st+1,st+1+top,x)-st;}
void insert(int x,int v)
{
    for(int i=x;i<=top;i+=i&-i)
        tr[i]+=v;
}
int query(int x)
{
    int ret=1;
    for(int i=x;i;i-=i&-i)
        ret+=tr[i];
    return ret;
}
int main()
{
    scanf("%d%lf",&n,&d);
    for(int i=1;i<=n;i++)
    {
        double a,b,c;
        scanf("%lf%lf%lf",&a,&b,&c);
        l[i].v=poi(b,-a);
        if(a)l[i].p=poi(-c/a,0);
        else l[i].p=poi(0,-c/b);
        l1.v=poi(a,b);
        poi p1=intersect(l[i],l1);
        if(p1.dis()>d*d)continue;
        double dis=sqrt(d*d-p1.dis());
        p[++cnt].x=move(p1,l[i].v,dis).alp();
        p[cnt].y=move(p1,l[i].v,-dis).alp();
        if(p[cnt].x>p[cnt].y)swap(p[cnt].x,p[cnt].y);
        st[++top]=p[cnt].x;st[++top]=p[cnt].y;
    }
    sort(p+1,p+1+cnt);
    sort(st+1,st+1+top);
    for(int i=1;i<=cnt;i++)
    {
        ans+=query(get(p[i].y))-query(get(p[i].x)-1);
        insert(get(p[i].y),1);
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值