[NOI.AC省选模拟赛3.31] 星辰大海 [半平面交]

题面

传送门

思路

懒得解释了......也是比较简单的结论

但是自己看到几何就退缩了......

下周之内写一个计算几何的学习笔记!

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<cmath>
#define eps 1e-14
using namespace std;
inline int read(){
	int re=0,flag=1;char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') flag=-1;
		ch=getchar();
	}
	while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
	return re*flag;
}
/*
Calculating the intersection of two segments:
method 1:	Brute force implemention -> get 4 equations, take the position of target point as the unknown factor
method 2:	Solve using vector -> the 'x-multiple' of two planary vectors is the SIGNED area of the paralellogram formed by them.
			ALWAYS MIND the sign before the area (refer to function cross(seg,seg) for further detail)
*/
int T,N,n,m;
inline int sign(const long double &d){
	if(d>eps) return 1;
	if(d<-eps) return -1;
	return 0;
}
struct p{
	long double x,y;
	p(long double xx=0.0,long double yy=0.0){x=xx;y=yy;}
}rt[1000010];
inline p operator *(const p &a,const long double &b){return p(a.x*b,a.y*b);}
inline long double operator *(const p &a,const p &b){return a.x*b.y-a.y*b.x;}//'x-multiple' of planary vector
inline p operator -(const p &a,const p &b){return p(a.x-b.x,a.y-b.y);}
inline p operator +(const p &a,const p &b){return p(a.x+b.x,a.y+b.y);}
struct ele{
	p a;long double k;
}lis[1000010];
struct seg{
	p a,b;long double k;
	seg(p aa=p(),p bb=p(),long double kk=0.0){a=aa;b=bb;k=kk;}
}a[1000010],q[1000010];
inline long double getk(const p &a){return atan2l(a.y,a.x);}//get the k-value of a pair<long double,dobule>
inline bool cmp(const ele &l,const ele &r){return l.k<r.k;}
inline bool operator <(const seg &l,const seg &r){return l.k<r.k;}//sort according to k
inline p cross(const seg &x,const seg &y){//calculate the intersection using planary vector
	long double v1=(x.a-y.b)*(x.b-y.b);
	long double v2=(x.a-y.a)*(x.b-y.a);
	long double c=v1/(v1-v2);
	p re=(y.b+((y.a-y.b)*c));
	return re;
}
inline bool right(const p &x,const seg &y){//determine if x is to the right of y
	return ((x-y.a)*(x-y.b))>=0;
}
inline long double solve(){
	int i,head=1,tail=0,flag;long double re=0;
	sort(a+1,a+m+1);
	for(i=1;i<=m;i++){
		flag=0;
		while(head<=tail&&(!sign(a[i].k-q[tail].k))){//get rid of segments at same k
			if((q[tail].a-a[i].a)*(q[tail].a-a[i].b)>=0) tail--;//if old one is to the right of current one, delete it
			else{flag=1;break;}//or else, the current one shall be deleted
		}
		if(flag) continue;
		while(head<tail&&right(rt[tail],a[i])) tail--;//check if the intersection is to the right, if so delete the foremost/backmost segment
		while(head<tail&&right(rt[head+1],a[i])) head++;
		q[++tail]=a[i];
		if(head<tail) rt[tail]=cross(q[tail-1],q[tail]);
	}
	while(head<tail&&right(rt[tail],q[head])) tail--;
	while(head<tail&&right(rt[head+1],q[tail])) head++;
	rt[head]=rt[tail+1]=cross(q[head],q[tail]);//mind that the first and last points are adjacent
	for(i=head;i<=tail;i++){
		re+=rt[i]*rt[i+1];
	}
	return re;
}
const long double pi=acosl(-1.0);
const p ur(1e6,1e6);
const p ul(-1e6,1e6);
const p dr(1e6,-1e6);
const p dl(-1e6,-1e6);
const seg rr(ur,dr,-pi*0.5);
const seg dd(dr,dl,pi);
const seg ll(dl,ul,pi*0.5);
const seg uu(ul,ur,0);
int main(){
	N=read();T=read();int flag,i,j;
	while(T--){
		n=read();
		m=0;
		a[++m]=rr;a[++m]=dd;a[++m]=ll;a[++m]=uu;
		for(i=1;i<=n;i++){
			lis[i].a.x=read();
			lis[i].a.y=read();
		}
		for(i=2;i<=n;i++){
			lis[i].k=getk(lis[i].a-lis[1].a);
		}
		sort(lis+2,lis+n+1,cmp);
		for(i=2;i<=n;i++){
			lis[i+n-1]=lis[i];
			lis[i+n-1].k+=2.0*pi;
		}
		flag=1;j=2;
		for(i=2;i<=n;i++){
			j=max(i,j);
			while(lis[j+1].k-lis[i].k<pi+eps) j++;
			if((!sign(lis[i+1].k-lis[i].k))||(!sign(lis[i].k+pi-lis[j].k))){
				flag=0;puts("0");break;
			}
			if(j!=i) a[++m]=seg(lis[j].a,lis[i].a,getk(lis[i].a-lis[j].a));
			if(lis[i+1].k-lis[i].k<pi+eps) a[++m]=seg(lis[i+1].a,lis[i].a,getk(lis[i].a-lis[i+1].a));
		}
		if(flag) printf("%.9lf\n",(double)solve()*0.5);
	}
}
posted @ 2019-03-31 22:05  dedicatus545  阅读(174)  评论(0编辑  收藏  举报