貌似出题人给的方法一点都不友好QwQ
那个如果一个平面是有限的,那么它被分为两部分,这两部分都是有限的。
假设我们要求的那条直线是y轴(不是也可以转),那么考虑对直线左右分别计算平面是否有限。
就直线右侧而言,我们把交点按照顺序排好。交点
ya
和
yb
之间的区间对应平面是有限的,当且仅当存在
yc
和
yd
,满足
yd≤yb≤ya≤yc
,且
kc<kd
。
其中c,d可以是a,b,k代表交点对应直线斜率。
感性认识一下吧……
那么先说一下把要求的直线旋到y轴的原因:好判断啊,一边的直线斜率全是连续的了。但是旋转后平行难判,要用原始坐标判断。
那么考虑一下如何维护相交。
我们肯定是维护一个数据结构,然后来去除掉一些我们不需要的信息。那么看看下图所示的情况:
如图所示,红线(a)和黑线(b)是已经处理完的直线,然后现在要进行计算的是蓝线(c)
红线和黑线满足于这个关系
yb<ya
且
ka<kb
那么蓝线如果要交黑线,肯定可以交红线,而且交红线可以封闭
[ya,yc]
这一段区间(别吐槽我区间左右反过来的问题,我是从上往下考虑的),封闭的区间比与黑线交封闭的更大。
那么实际上我们只是需要维护一个序列(栈),满足点对应的直线斜率递减,加入序列的顺序是从y坐标大到小依次加入。
当有一条新直线来的时候,在序列中二分能交到哪,给区间头尾打个标记(相当于差分)。
假如一条都交不到,加入序列(说明这条线斜率是目前最小)
直线左侧做法和右侧是完全一样的,但是判断与右侧相反
最后按顺序扫一下,假如直线两侧对应的区间都是有限,说明这段是有限的,反之无限。
#include<stdio.h>
#include<cmath>
#include<algorithm>
#define now e[i].k
#define N 100005
#define eps 0.00000000001
using namespace std;
bool f[N];
int l,r,mid,n,d[N],t,p[N];
long double x1[N],Y1[N],x2[N],y2[N],x,y;
long long XX1[N],YY1[N],XX2[N],YY2[N];
struct mpoi
{
long double pos;
int k;
friend bool operator < (mpoi a,mpoi b){return a.pos>b.pos;}
}e[N];
inline void getpoi(const int &i){e[i].pos=Y1[i]-x1[i]*(Y1[i]-y2[i])/(x1[i]-x2[i]);now=i;}
inline bool cmp(const int &i,const int &j)
{
return (XX1[i]-XX2[i])*(YY1[j]-YY2[j])!=(XX1[j]-XX2[j])*(YY1[i]-YY2[i]) &&
(Y1[i]-y2[i])*(x1[j]-x2[j])<(Y1[j]-y2[j])*(x1[i]-x2[i]);
}
inline void judge(const int &f)
{
d[t=1]=1;
for (int i=2;i<n;i++) if (f?cmp(e[d[t]].k,now):cmp(now,e[d[t]].k))
{
for (l=1,r=t,mid=t+1>>1;l<r;mid=l+r>>1) if (f?cmp(e[d[mid]].k,now):cmp(now,e[d[mid]].k)) r=mid;
else l=mid+1;
p[e[d[l]+1].k]++;p[e[i+1].k]--;
}
else d[++t]=i;
}
int main()
{
scanf("%d",&n);n++;
for (int i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld",XX1+i,YY1+i,XX2+i,YY2+i);
x1[i]=XX1[i];Y1[i]=YY1[i];x2[i]=XX2[i];y2[i]=YY2[i];
}
for (int i=1;i<=n;i++) x2[i]-=x1[n],x1[i]-=x1[n],y2[i]-=Y1[n],Y1[i]-=Y1[n];
long double th=atan((Y1[n]-y2[n])/(x1[n]-x2[n]))+3.14159265358979/2;
for (int i=1;i<=n;i++)
{
x=x1[i]*cos(th)+Y1[i]*sin(th);
y=Y1[i]*cos(th)-x1[i]*sin(th);
x1[i]=x;Y1[i]=y;
x=x2[i]*cos(th)+y2[i]*sin(th);
y=y2[i]*cos(th)-x2[i]*sin(th);
x2[i]=x;y2[i]=y;
}
for (int i=1;i<n;i++)
{
if (x2[i]<x1[i]) swap(x1[i],x2[i]),swap(Y1[i],y2[i]);
getpoi(i);
}
sort(e+1,e+n);
judge(1);
for (int i=1,tag=0;i<=n;p[e[i++].k]=0) if (tag+=p[now]) f[now]=1;
judge(0);
for (int i=1,tag=0;i<=n;i++) putchar(((tag+=p[now]) && f[now])?'1':'0');
}