hdu3465Life is a Line(树状数组)

来源:互联网 发布:淘宝代码素材 编辑:程序博客网 时间:2024/04/29 12:26

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3465

题目大意:

给一个开区间(l,r),给n个直线,问这些直线在这段区间里面有多少个交点。

思路:

对于两条直线来说,我们可以求出他们分别于y=l,y=r的交点a,b,c,d。如果a<c&&b>d或者a>c&&b<d,那么说明他们一定是有交点的。所以我们就可以从这里入手,把直线与两个区间的交点处理出来,然后利用树状数组进行更新计算。方法是先按照x从大到小排序,然后按照y从大到小排序(y从大到小是为了保证当x相同的时候,能够先把y大的放入树状数组中),然后直接树状数组更新求和。

注意要把与y轴平行的数量也算进去。

代码:

#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>#include<math.h>using namespace std;int N;double L,R;struct node{    double x,y;    int X,Y;}p[50005];bool cmp(node a,node b){    if(a.X==b.X)return a.Y>b.Y;    return a.X>b.X;}int d[200005];double a[100005];int lowbit(int x){    return x&(-x);}void update(int x,int n){    while(x<=n){        d[x]++;        x+=lowbit(x);    }}int getsum(int x){    int ans=0;    while(x>0){        ans+=d[x];        x-=lowbit(x);    }    return ans;}int main(){    double x1,y1,x2,y2;    int tt,tot,xx;    while(~scanf("%d",&N)){        memset(d,0,sizeof(d));        tt=0;        tot=0;        xx=0;        scanf("%lf%lf",&L,&R);        for(int i=1;i<=N;i++){            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            if(x1==x2){                if(x1>L&&x1<R)xx++;                continue;            }            double K=(y2-y1)/(x2-x1)*1.0;            p[++tt].x=K*L+y1-K*x1;            a[++tot]=p[tt].x;            p[tt].y=K*R+y1-K*x1;            a[++tot]=p[tt].y;                    }        sort(a+1,a+1+tot);        tot=unique(a+1,a+1+tot)-a-1;        for(int i=1;i<=tt;i++){            p[i].X=lower_bound(a+1,a+1+tot,p[i].x)-a;            p[i].Y=lower_bound(a+1,a+1+tot,p[i].y)-a;        }        int ans=0;        sort(p+1,p+1+tt,cmp);        for(int i=1;i<=tt;i++){            ans+=getsum(p[i].Y-1);            update(p[i].Y,tot);        }        printf("%d\n",ans+xx*tt);    }    }


0 0
原创粉丝点击