ZOJ 3157 Weapon --计算几何+树状数组

题意:给一些直线,问这些直线在直线x=L,x=R之间有多少个交点。

讲解见此文:http://blog.sina.com.cn/s/blog_778e7c6e0100q64a.html

首先将直线分别跟x=L+eps,x=R-eps(防止出现相同纵坐标,故+-eps)求他们的交点,求的纵坐标为low,high,首先按low从大到小排序,一次赋予一个ind值,再按high从大到小排序,此时ind的逆序对数即为(L,R)内的交点个数。成功将计算几何问题向树状数组转化。求逆序对数可用归并排序或者树状数组解决。

代码:(树状数组)

#include <iostream>

#include <cmath>

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#define eps 1e-5

using namespace std;

#define N 10007



struct node

{

    double x,y;

};



struct Line

{

    node a,b;

    int ind;

    double low,high;

}line[N];



int c[N],n;



int cmp(Line ka,Line kb)

{

    return ka.low > kb.low;

}



int cmp2(Line ka,Line kb)

{

    return ka.high > kb.high;

}



int lowbit(int x){ return x & (-x); }



void modify(int x)

{

    while(x <= n)

        c[x]++,x += lowbit(x);

}



int getsum(int x)

{

    int res = 0;

    while(x > 0)

        res += c[x],x -= lowbit(x);

    return res;

}



int main()

{

    int i,x,j;

    double L,R;

    while(scanf("%d",&n)!=EOF)

    {

        memset(c,0,sizeof(c));

        for(i=1;i<=n;i++)

            scanf("%lf%lf%lf%lf",&line[i].a.x,&line[i].a.y,&line[i].b.x,&line[i].b.y);

        scanf("%lf%lf",&L,&R);

        L += eps,R -= eps;

        for(i=1;i<=n;i++)

        {

            double k = (line[i].b.y-line[i].a.y)/(line[i].b.x-line[i].a.x);

            line[i].low = k*(L-line[i].a.x) + line[i].a.y;

            line[i].high = k*(R-line[i].a.x) + line[i].a.y;

        }

        sort(line+1,line+n+1,cmp);

        for(i=1;i<=n;i++)

            line[i].ind = i;

        sort(line+1,line+n+1,cmp2);

        int ans = 0;

        for(i=1;i<=n;i++)

        {

            modify(line[i].ind);

            ans += i - getsum(line[i].ind);

        }

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(树状数组)