【纪中集训2019.3.30】星辰大海

题目

描述

​ 有(n)个点(p_1 ,p_2 , cdots ,\,p_n)

​ 现在(p_1)不见了,可能的横纵坐标范围是([-10^6,10^6])

​ 同时需要保证每三个点形成的有向角的符号不改变;

​ 问(p_1)可能范围的区域;

范围

(1 le T le 1000 , 3 le N , sum N le 5 imes 10^5 , |x_i|,|y_i| le 10^6)

​ 误差范围:(10^{-6}),建议eps取([10^{-15},10^{-12}])

题解

  • (p_1)为原点,得到$p_2-p_1,p_3-p_1, cdots ,p_n - p_1 $ ;
  • 问题即求两两点的原点部分的半平面交;
  • 将新的(p_1,p_2, cdots, p_n)按照极角排序;
  • 只需要考虑1.(p_i-p_{i+1}),以及2.和(p_i)极角相差不超过(pi) 的最远点和(p_i)组成的半平面;
  • 简要证明一下:
    • 假设(p_a-p_b(a<b-1))有效却没有被考虑到,并且在(ab)中间的并没有漏掉的半平面;
    • 同时假设原点在左半平边;
    • 那么( riangle p_ap_bO)里面一定不能有点,否则假设为(p_c(a<c<b))
    • 那么(p_c-p_b和p_a-p_c)会使其无效;
    • 所以一定存在(p_c(a<c<b))在$ riangle $的外面;
    • 由于(p_b)没有被(2)考虑到,所以一定同时存在(p_d)(2)考虑到了;
    • 那么(p_a-p_c,p_a-p_d)会使其无效;

一点想法

能不能对所有的(i=1-n)求答案呢?;

感觉可以拓展的样子;

//我的半平面交好像很慢的样子QAQ;
#include<bits/stdc++.h>
#define ld double
#define eps 1e-15
#define il inline 
using namespace std;
const int N=1000010;
int C,T,n,m,st[N],hd,tl;
const ld pi=acos(-1);
il int dcmp(ld x){return fabs(x)<eps?0:x<0?-1:1;}
struct P{
	ld x,y;ld ang;
	P(ld _x=0,ld _y=0):x(_x),y(_y){ang=atan2(y,x);};
	P operator -(const P&A)const{return P(x-A.x,y-A.y);}
	P operator +(const P&A)const{return P(x+A.x,y+A.y);}
	P operator *(const ld&A)const{return P(x*A,y*A);}
	il bool operator <(const P&A)const{return dcmp(ang-A.ang)<0;}
}p[N],q[N];
ld crs(const P&a,const P&b){return a.x*b.y-a.y*b.x;}
struct L{
	int a,b;ld ang;
	L(int _a=0,int _b=0):a(_a),b(_b){ang=atan2(p[b].y-p[a].y,p[b].x-p[a].x);}
	il bool operator <(const L&A)const{
		int d=dcmp(ang-A.ang);
		return !d?dcmp(crs(p[b]-p[a],p[A.b]-p[a]))<0:d<0;
	}
}l[N];
il char gc(){
	static char*p1,*p2,s[1000000];
	if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
	return(p1==p2)?EOF:*p1++;
}
il int rd(){
	int x=0,f=1;char c=gc();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=gc();}
	return x*f;	
}
il P get(const L&A,const L&B){
	P u=p[A.b]-p[A.a];
	P v=p[B.b]-p[B.a];
	P w=p[A.a]-p[B.a];
	ld d=crs(v,w)/crs(u,v);
	return p[A.a]+u*d;
}
il bool judge(const L&A,const P&B){
	P u=p[A.b]-p[A.a];
	P v=B-p[A.a];
	return dcmp(crs(u,v))<=0;
}
il void add(int x,int y){
	if(judge(L(x,y),P(0,0)))l[++m]=L(y,x);
	else l[++m]=L(x,y);
}
int main(){
	freopen("everdream.in","r",stdin);
	freopen("everdream.out","w",stdout);
	C=rd();T=rd();
	while(T--){
		n=rd();
		p[0].x=rd();p[0].y=rd();
		for(int i=1,x,y;i<n;++i){
			x=rd();y=rd();
			x-=p[0].x;y-=p[0].y;
			p[i]=P(x,y);
		}
		--n;m=0;sort(p+1,p+n+1);
		for(int i=1;i<=n;++i)p[i+n]=p[i],p[i+n].ang+=2*pi;
		int fg=0;
		for(int i=1;i<=n;++i){
			if(!dcmp(p[i].ang-p[i+1].ang)){fg=1;break;}
			add(i,i%n+1);
			P tmp=P(0,0);tmp.ang=p[i].ang+pi-eps; 
			int j=lower_bound(p+1,p+n*2+1,tmp)-p;
			if(i+n!=j&&!dcmp(p[j].ang-p[i].ang-pi)){fg=1;break;}
			--j;if(i!=j&&i+n!=j)add(i,(j-1)%n+1);
		}
		if(fg){puts("0.0000000000");continue;}
		p[n+1]=(P){-1e6,-1e6};p[n+2]=(P){1e6,-1e6};
		p[n+3]=(P){1e6,1e6};p[n+4]=(P){-1e6,1e6};
		p[n+1]=p[n+1]-p[0];p[n+2]=p[n+2]-p[0];
		p[n+3]=p[n+3]-p[0];p[n+4]=p[n+4]-p[0];
		add(n+1,n+2),add(n+2,n+3);
		add(n+3,n+4),add(n+4,n+1);
		sort(l+1,l+m+1);
		hd=tl=0;st[++tl]=1;
		for(int i=2;i<=m;++i)if(dcmp(l[i].ang-l[i-1].ang)){
			while(hd<tl-1 && judge( l[i] , get(l[st[tl]],l[st[tl-1]]) ) )tl--;
			while(hd<tl-1 && judge( l[i] , get(l[st[hd+1]],l[st[hd+2]]) ) )hd++;
			st[++tl]=i;
		}
		while(hd<tl-2 && judge( l[st[hd+1]] , get(l[st[tl]] , l[st[tl-1]]) ) )tl--;
		while(hd<tl-2 && judge( l[st[tl]] , get(l[st[hd+1]] , l[st[hd+2]]) ) )hd++;
		if(tl-hd<=2){puts("0.0000000000");continue;}
		n=0;st[tl+1]=st[hd+1];
		for(int i=hd+1;i<=tl;++i)q[++n]=get(l[st[i]],l[st[i+1]]);
		ld ans=0;q[n+1]=q[1];
		for(int i=1;i<=n;++i)ans+=crs(q[i],q[i+1]);
		ans/=2;
		printf("%.10lf
",ans);
	}
	//printf("%.2lf
",1.0*clock()/CLOCKS_PER_SEC);
	return 0;
}
原文地址:https://www.cnblogs.com/Paul-Guderian/p/10637835.html