NKOJ-Unknow 直线的交点

来源:互联网 发布:三菱系统攻丝编程实例 编辑:程序博客网 时间:2024/06/14 11:23

直线的交点
问题描述

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

输入格式

第一行三个整数 k,a,b 表示平板的两条平行直线的方程为 y=kx+a 和 y=kx+b,保证 a<b。第二行一个整数 n。接下来 n 行每行两个整数 ki,bi 表示第 i 条直线的方程 y=kix+bi。

输出格式

一个整数,表示有多少对直线,他们的交点在平板之间。

样例输入

0 3 5051 02 0-1 0-2 0-1 10

样例输出

3

样例解释

只有 y=-x+10 这条直线和 y=x,y=2x,y=-2x 这三条直线的交点在区域内。

数据范围与约定

对于 30% 的数据, n≤5000。对于 100% 的数据, n≤100000。为了简单起见,输入数据保证,没有直线和平板平行,没有两条直线的交点在平板上。

像这种题就是给我做我都不会做

题解

简化题意

由于上下两条线是平行的
所以 可以自己画两条平行线
然后按照和上平行线的交点的顺序 一条一条加进去

然后你就会惊奇地发现

每加入一条直线 新增的交点数=之前的直线数量-加入的直线与下平行线交点的左边的交点数

没什么好证明的 观察就能知道是为什么

假设直线LA与上平行线的交点在LB与上平行线的交点左边那么    LB与下平行线的交点在LA与下平行线的交点的左边时 就有交点    反之则没有

而上面 之前的直线数量-加入的直线与下平行线交点的左边的交点数 即为 与下平行线的交点在多少条直线的左边
注意 我们是按照和上平行线交点的顺序依次加入直线的 所以上述证明过程绝对可以普遍化

于是 这就变成了一道简单的树状数组题

解法

求出每条直线和上下平行线的交点 并按照和上平行线的交点的顺序排序

对于每条直线

统计 之前的直线数量-当前直线与下平行线交点的左边的交点数 ->加入结果将当前的下交点加入树状数组

而下交点的位置需要离散化 即 它的新位置由 排序后 lower_bound求出的位置 表示

总结

这道题目其实很简单 关键在于对交点数判定的简化过程(其实这个过程中考好像就有涉及)
其次的操作是离散化 这个操作很普遍 需要熟练掌握

附上对拍代码(比题解麻烦很多,最好不要看)

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#define mid (l+r>>1)#define lowbit(x) (x&-x)using namespace std;inline int input(){    char c=getchar();int o;bool f=0;    while(c>57||c<48)f|=(c=='-'),c=getchar();    for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;    return f?-o:o;}struct li{double k,b;}line[101234],nline,up,down;struct cut{double a,b;int mk;}pots[101234];bool cp(cut a,cut b){return a.a<b.a;}double dx,pot[201234];int all=0,ap,ll,rr,p;int shang[201234],xia[201234];void add(cut a){    for(int x=a.a;x<=ap;x+=lowbit(x))shang[x]++;    for(int x=a.b;x<=ap;x+=lowbit(x))xia[x]++;}int sum(cut a){    int ansA=0,ansB=0;    for(int x=a.a;x;x-=lowbit(x))ansA+=shang[x];    for(int x=a.b;x;x-=lowbit(x))ansB+=xia[x];    return abs(ansA-ansB);}double jiao(li a,li b){return (b.b-a.b)/(a.k-b.k);}void addp(li a){    pots[++all].a=jiao(a,down);    pots[all].b=jiao(a,up)+dx;}int main(){    freopen("point.in","r",stdin);    freopen("point.out","w",stdout);    int n;long long res=0;    double k;    k=down.k=up.k=input();down.b=input();up.b=input();    dx=(up.b-down.b)*k/(1+k*k);    n=input();    for(int i=1;i<=n;i++)nline.k=input(),nline.b=input(),addp(nline);    for(int i=1;i<=n;i++)pot[i<<1]=pots[i].b,pot[(i<<1)-1]=pots[i].a;    ap=all<<1;    sort(pot+1,pot+ap+1);    for(int i=1;i<=n;i++)    {        pots[i].a=lower_bound(pot+1,pot+ap+1,pots[i].a)-pot;        pots[i].b=lower_bound(pot+1,pot+ap+1,pots[i].b)-pot;    }    sort(pots+1,pots+all+1,cp);    for(int i=1;i<=all;i++)    {        res+=sum(pots[i]);        add(pots[i]);    }    printf("%lld",res);}
原创粉丝点击