您的位置:首页 > 其它

【UOJ】#242. 【UR #16】破坏蛋糕

2017-01-19 22:57 351 查看
传送门http://uoj.ac/problem/242

貌似出题人给的方法一点都不友好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
;
int l,r,mid,n,d
,t,p
;
long double x1
,Y1
,x2
,y2
,x,y;
long long XX1
,YY1
,XX2
,YY2
;

struct mpoi
{
long double pos;
int k;
friend bool operator < (mpoi a,mpoi b){return a.pos>b.pos;}
}e
;

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
,x1[i]-=x1
,y2[i]-=Y1
,Y1[i]-=Y1
;
long double th=atan((Y1
-y2
)/(x1
-x2
))+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');
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: