直线的交点 计蒜客提高组模拟赛(三)Day2 逆序对 归并排序

伦伦刚刚在高中学习了解析几何,学会了计算两条直线的交点。这天,老师给她布置了一道作业。在平面上有 n 条直线,他们之间有若干交点。给定一对平板(两条平行的直线),问这有多少对直线,他们的交点在这一对平板之间(注意 (i, j) 和 (j, i) 只算一对)。

还记得一道河两边的什么鬼的逆序对的题吗?

我们设一对平板的代号分别为X、Y。

对于每一条直线,我们可以解出它在X、Y上的交点的横坐标,用一个struct T存下来。

我们按照X上面的交点横坐标排序T

然后给T在Y上面的交点横坐标做归并排序,逆序对个数就是焦点个数,而一个焦点就对应了一对合法直线,所以答案就是逆序对个数。

为什么逆序对个数是焦点个数?

因为X上面的坐标排列是有序的,从小到大的。对于Y上面的坐标,如果出现一个逆序对,他们一定能够产生焦点(可以自己画图验证一下)。

附上AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
template<class T> inline void read(T &_a){
    bool f=0;int _ch=getchar();_a=0;
    while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();}
    while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();}
    if(f)_a=-_a;
}

const int maxn=100001;
int n;
long long ans;
struct node
{
    double x1,x2;
    inline bool operator < (const node x) const {return x1<x.x1;}
}res[maxn];
double k1,a1,b1,k,b,T[maxn];

void merge(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    merge(l,mid);
    merge(mid+1,r);
    int i=l,j=mid+1,q=l;
    while(i<=mid&&j<=r)
    {
        if(res[i].x2>res[j].x2)
        {
            ans+=mid-i+1;
            T[q++]=res[j++].x2;
        } else T[q++]=res[i++].x2;
    }
    while(i<=mid) T[q++]=res[i++].x2;
    while(j<=r) T[q++]=res[j++].x2;
    for (register int i=l;i<=r;++i) res[i].x2=T[i];
}

int main()
{
    freopen("point.in","r",stdin);
    freopen("point.out","w",stdout);
    scanf("%lf%lf%lf",&k1,&a1,&b1);
    read(n);
    for (register int i=1;i<=n;++i)
    {
        scanf("%lf%lf",&k,&b);
        res[i].x1=(b-b1)/(k1-k);
        res[i].x2=(b-a1)/(k1-k);
    }
    sort(res+1,res+n+1);
    merge(1,n);
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/jaywang/p/7748447.html