HDU3465--Life is a Line(树状数组求逆序数,离散化)

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)

Total Submission(s): 201 Accepted Submission(s): 77

Problem Description

There is a saying: Life is like a line, some people are your parallel lines, while others are destined to meet you.
Maybe have met, maybe just a matter of time, two unparallel lines will always meet in some places, and now a lot of life (i.e. line) are in the same coordinate system, in a given open interval, how many pairs can meet each other?

Input

There are several test cases in the input.
Each test case begin with one integer N (1 ≤ N ≤ 50000), indicating the number of different lines.
Then two floating numbers L, R follow (-10000.00 ≤ L < R ≤ 10000.00), indicating the interval (L, R).
Then N lines follow, each line contains four floating numbers x1, y1, x2, y2 (-10000.00 ≤ x1, y1, x2, y2 ≤ 10000.00), indicating two different points on the line. You can assume no two lines are the same one.
The input terminates by end of file marker.

Output

For each test case, output one integer, indicating pairs of intersected lines in the open interval, i.e. their intersection point’s x-axis is in (l, r).

Sample Input

3
0.0 1.0
0.0 0.0 1.0 1.0
0.0 2.0 1.0 2.0
0.0 2.5 2.5 0.0

Sample Output

1

Author

iSea @ WHU

Source

2010 ACM-ICPC Multi-University Training Contest(3)——Host by WHU

Recommend

zhouzeyong

题意:

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

思路:

如果暴力求解的话,时间复杂度为n^2,大概为10^11,肯定会超时。

由于题目将x的坐标限定在了一个区间(l,r)内,考虑如下情况:

设直线1分别与x=l,x=r相交与L1,R1;直线2分别相交于L2,R2。若两直线在此区间内相交,必有

L1<L2&&R1>R2  或者  L1>L2&&R1<R2

(想象若两直线在(l,r)相交,则经过交点后,纵坐标的大小顺序一定会改变)

此即为逆序数对的性质,于是题目转化为了求逆序数对的个数:

还需注意两点:

1.与y轴平行的,只要这样的线在(l,r)范围内,则必定跟别的不平行线相交。所以计算下个数再乘以不与y轴平行的线的个数  2.就能使在l和r上的交点不计算在内,需要在排序时注意下(当l相同时,按r排序;当r相同时,按l排序)

另外很重要的一点,数据为实型数,需要对数据进行离散化处理,如此才能应用树状数组

关于离散化:http://blog.csdn.net/gokou_ruri/article/details/7723378

代码:

#include<bits/stdc++.h>
    using namespace std;

    #define lowbit(x) (x&(-x))
    const int N=5e4+10;
    struct node{
        double a,b;
        int num;
    };
    node e[N];
    int c[N];
    double l,r;

    int cmp1(node x,node y) //left 递增排序
    {
        if(x.a==y.a)
            return x.b<y.b;
        return x.a<y.a;
    }

    int cmp2(node x,node y) //right 递减排序
    {
        if(x.b==y.b)
            return x.a>y.a;
        return x.b>y.b;
    }

    void add(int x,int val)
    {
        while(x<N)
        {
            c[x]+=val;
            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;
        int t,tt,i,j,ans;
        double x1,y1,x2,y2,k,b;

        while(scanf("%d",&n)!=EOF)
        {
            t=tt=0;
            ans=0;
            scanf("%lf%lf",&l,&r);
            for(i=0;i<n;i++)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);//两个点的横纵坐标
                if(x1==x2)//横坐标相等  表示竖直的线 平行与y轴
                {
                    if(l<x1&&x1<r)
                        tt++;
                    continue;
                }
                k=(y2-y1)/(x2-x1);//y=kx+b
                b=y1-k*x1;
                e[t].a=l*k+b;
                e[t++].b=r*k+b;
            }
            //******************//
            //离散化,由于想树状数组中add的是left,所以只对left离散化即可
            sort(e,e+t,cmp1);
            for(i=0;i<t;i++)//编号
                e[i].num=i+1;//树状数组无下标0
            //*******************//
            sort(e,e+t,cmp2);//递减排序 3412
            memset(c,0,sizeof(c));
            for(i=0;i<t;i++)//统计
            {
                add(e[i].num,1);
                ans+=sum(e[i].num-1);
            }
            printf("%d\n",ans+tt*t);//加上平行y轴的直线所产生的交点
        }
    }

转载于:https://www.cnblogs.com/liuzhanshan/p/6406564.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值