jzoj1896. 大灾变

题目描述

Description
  艾泽拉斯世界经历一场亘古未有的地震过后,大地和海洋被完全撕裂,旧大陆残缺不全。联盟和部落各种族的居民们被迫离开了世代居住的家园,来寻找新的生存空间。原本平坦的陆地上现在隆起了一座座山峰,暴风城的人类开始在艾尔文山脉重建家园。他们决定在山脉之中建造一座瞭望塔和一个魔法浮空岛,以便于在瞭望塔和浮空岛上可以俯视艾尔文山脉的全貌。
  艾尔文山脉被描述为一个折线,给定每个点的坐标(横纵坐标均不小于0),按照横坐标从小到大顺次连接起来就是就是山脉的折线。折线上所有点的横坐标均不相同。如果一个位置与山脉任何一点的连线均不被挡住(但可以与地面相切),那么就说这一点可以望到整个艾尔文山脉。瞭望塔的塔身不会挡住视线,而且瞭望塔和浮空岛可以建造在同一位置。为节省建筑材料,瞭望塔塔身的高度必须尽量小,即从塔顶到塔底的距离尽量小,瞭望塔可以建在山坡上。由于气候因素,浮空岛应建立在海拔尽量低的位置(甚至可以建在地面上),海平面高度为0。如果有多个位置均满足条件,则选择横坐标最小的那个。瞭望塔和浮空岛横坐标范围应在艾尔文山脉横坐标范围之内。
  给定艾尔文山脉,请你求出瞭望塔和浮空岛的位置。

Input
  第1行,一个整数N,表示描述艾尔文山脉的折线的顶点数。
  第2-N+1行,每行两个整数,xi,yi表示折线上点的坐标。

Output
  第1行,两个保留2位小数的浮点数x1,y1,表示瞭望塔顶端的坐标。
  第2行,两个保留2位小数的浮点数x2,y2,表示浮空岛的坐标。

Sample Input
6
2 2
6 1
8 6
10 3
16 5
20 2

Sample Output
8.00 11.00
9.54 9.85

Data Constraint

Hint
【样例说明】   样例中描述的艾尔文山脉各个顶点,按照横坐标顺序顺次连接后的折线如下图所示:
在这里插入图片描述
瞭望塔应建造在山峰(8,6)处,塔顶端为(8,11),高度为5,此时瞭望塔的高度最小。      
在这里插入图片描述
浮空岛建立在(9.54,9.85)处,海拔高度最低。
在这里插入图片描述

【数据规模】
  40%的数据2<=N<=10
  100%的数据2<=N<=1 000 000;
0<=xi,yi<=5 000 000

题解

半平面交裸题
而且只有下凸壳所以不用队列

浮空岛就是凸壳最低点
瞭望塔的x只可能是下凸壳/原点中的某个x
加上凸壳的首尾两个点,排序后单调找,每次找相邻的一类点中间的其它点来求交

然鹅
本题的坑点在于时间/空间/精度
在这里插入图片描述
自己感受
在这里插入图片描述
在这里插入图片描述
上面两个是同一个程序

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define cj(a,b,c) ((c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y))
#define abs(x) ((x)>0?(x):-(x))
#define max(a,b) (a>b?a:b)
#define pi 3.14159265358979323846
#define E 0.0000001
using namespace std;

struct P{
	double x,y;
	P (double _x=0,double _y=0) {x=_x,y=_y;}
} O=P(0,0),p[100001],Jd,A[1000001];
struct P2{
	double x,y;
	int type;
} b[2000001];
struct L{
	P s1,s2;
	float xl;
	L (double _x1=0,double _y1=0,double _x2=0,double _y2=0) {s1.x=_x1,s1.y=_y1,s2.x=_x2,s2.y=_y2;}
} a[1000001],l1,l2; //s1-->s2
int N,n,i,j,k,l,t,tot,ls1,ls2;
double ans1,ans1x,ans1y,ans2,ans2x,ans2y,s;
long double s1,s2,S;
char ch[16000001];
char *Ch=ch;

int getint()
{
	int x=0;
	
	while (*Ch<'0'  || *Ch>'9' ) *++Ch;
	while (*Ch>='0' && *Ch<='9') x=x*10+(*Ch-'0'),*++Ch;
	
	return x;
}

//long double cj(P a,P b,P c)
//{
//	long double s=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
//	
//	if (abs(s)<=E)
//	return 0;
//	else
//	return s;
//}

bool cmp(L a,L b)
{
	return abs(a.xl-b.xl)>E && a.xl<b.xl || abs(a.xl-b.xl)<=E && cj(a.s1,a.s2,b.s2)<0;
}
bool Cmp(P2 a,P2 b)
{
	return a.x<b.x;
}
bool CMP(P a,P b)
{
	return a.x<b.x;
}

P jd(L a,L b)
{
	s1=cj(a.s1,b.s1,a.s2),s2=cj(a.s1,a.s2,b.s2);
	S=s1/(s1+s2);
	
	return P(b.s1.x+(b.s2.x-b.s1.x)*S,b.s1.y+(b.s2.y-b.s1.y)*S);
}

float xl(L a)
{
	float x=a.s2.x-a.s1.x,y=a.s2.y-a.s1.y;
	
	if (abs(y)<=E)
	{
		if (x>0)
		return 0;
		else
		return pi;
	}
	if (abs(x)<=E)
	{
		if (y>0)
		return pi/2;
		else
		return pi*3/2;
	}
	
	if (x>0 && y>0)
	return atan(y/x);
	if (x<0 && y>0)
	return atan(y/x)+pi;
	if (x<0 && y<0)
	return atan(y/x)+pi;
	if (x>0 && y<0)
	return atan(y/x)+pi+pi;
}

int main()
{
//	freopen("cataclysm38.in","r",stdin);
//	freopen("S8_2_3.in","r",stdin);
	
	fread(ch,1,16000001,stdin);
	
	n=getint();
	fo(i,1,n)
	A[i].x=getint(),A[i].y=getint();
	sort(A+1,A+n+1,CMP);
	
	N=0;
	fo(i,2,n)
	{
		++N;
		a[N]=L(A[i].x,A[i].y,A[i-1].x,A[i-1].y);
		a[N].xl=xl(a[N]);
	}
	
	sort(a+1,a+N+1,cmp);
	
	j=0;
	fo(i,1,N)
	if (i==1 || abs(a[i].xl-a[i-1].xl)>E)
	a[++j]=a[i];
	N=j;
	
	t=1;
	fo(i,2,N)
	{
		while (t>1 && cj(a[i].s1,a[i].s2,p[t-1])<=0)
		--t;
		
		a[++t]=a[i];
		p[t-1]=jd(a[t-1],a[t]);
	}
	
	tot=0;
	fo(i,1,n)
	{
		++tot;
		b[tot].x=A[i].x;
		b[tot].y=A[i].y;
		b[tot].type=0;
	}
	fo(i,1,t-1)
	{
		++tot;
		b[tot].x=p[i].x;
		b[tot].y=p[i].y;
		b[tot].type=1;
	}
	
	if (t==1 || p[1].x>A[1].x)
	{
		++tot;
		l1=L(A[1].x,A[1].y,A[1].x,233333333333333ll);
		Jd=jd(l1,a[1]);
		b[tot].x=Jd.x;
		b[tot].y=Jd.y;
		b[tot].type=1;
	}
	if (t==1 || p[t-1].x<A[n].x)
	{
		++tot;
		l1=L(A[n].x,A[n].y,A[n].x,233333333333333ll);
		Jd=jd(l1,a[t]);
		b[tot].x=Jd.x;
		b[tot].y=Jd.y;
		b[tot].type=1;
	}
	
	sort(b+1,b+tot+1,Cmp);
	
	ans1=233333333333333ll;
	ans2=233333333333333ll;
	
	ls1=0;
	ls2=0;
	fo(i,1,tot)
	{
		if (i<tot && abs(b[i].x-b[i+1].x)<=E)
		{
			s=abs(b[i].y-b[i+1].y);
			if (abs(s-ans1)>E && s<ans1 || abs(s-ans1)<=E && b[i].x<ans1x)
			{
				ans1=s;
				ans1x=b[i].x;
				ans1y=max(b[i].y,b[i+1].y);
			}
		}
		
		if (!b[i].type)
		{
			if (ls1)
			{
				fo(j,ls1+1,i-1)
				{
//					l1=L(b[j].x,-233333333333333ll,b[j].x,b[j].y);
//					l2=L(b[ls1].x,b[ls1].y,b[i].x,b[i].y);
//					
//					Jd=jd(l1,l2);
					
					Jd.x=b[j].x;
					Jd.y=b[ls1].y+(b[j].x-b[ls1].x)/(b[i].x-b[ls1].x)*(b[i].y-b[ls1].y);
					
					s=b[j].y-Jd.y;
					if (abs(s-ans1)>E && s<ans1 || abs(s-ans1)<=E && b[j].x<ans1x)
					{
						ans1=s;
						ans1x=b[j].x;
						ans1y=b[j].y;
					}
				}
			}
			ls1=i;
		}
		else
		{
			if (ls2)
			{
				fo(j,ls2+1,i-1)
				{
//					l1=L(b[j].x,233333333333333ll,b[j].x,b[j].y);
//					l2=L(b[ls2].x,b[ls2].y,b[i].x,b[i].y);
//					
//					Jd=jd(l1,l2);
					
					Jd.x=b[j].x;
					Jd.y=b[ls2].y+(b[j].x-b[ls2].x)/(b[i].x-b[ls2].x)*(b[i].y-b[ls2].y);
					
					s=Jd.y-b[j].y;
					if (abs(s-ans1)>E && s<ans1 || abs(s-ans1)<=E && Jd.x<ans1x)
					{
						ans1=s;
						ans1x=Jd.x;
						ans1y=Jd.y;
					}
				}
			}
			ls2=i;
			
			s=b[i].y;
			if (abs(s-ans2)>E && s<ans2 || abs(s-ans2)<=E && b[i].x<ans2x)
			{
				ans2=s;
				ans2x=b[i].x;
				ans2y=b[i].y;
			}
		}
	}
	
	if (abs(ans1x)<=E) ans1x=0;
	if (abs(ans1y)<=E) ans1y=0;
	if (abs(ans2x)<=E) ans2x=0;
	if (abs(ans2y)<=E) ans2y=0;
	
	printf("%0.2lf %0.2lf\n",ans1x,ans1y);
	printf("%0.2lf %0.2lf\n",ans2x,ans2y);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值