[CQOI2006]凸多边形

题目

wdnmd可算调出来了,以后我也是会半平面交的人了

由于给定的是一些凸包,我们直接按照逆时针把所有直线搞下来,我们默认保留直线左边的半平面;之后我们就可以按照极角序把直线排序,对于两条极角相等的直线,显然是更靠近左边的优,于是我们只保留最靠左的直线

与凸包不同的是,我们使用一个双端队列维护半平面交,对于一条要插入的直线\(l\),我们发现队尾两条直线的交点\(p\)\(l\)的右侧,那么就说明队尾的直线没啥用了,就弹出去;同理,如果队首两条直线的交点在\(l\)右侧,也将队首直线弹出

可以康康这个老哥博客里的图

最后还有可能出现队尾两条直线的交点在队首直线的右侧的情况,对于这种情况我们弹掉队尾就好了

代码

#include<bits/stdc++.h>
#define re register
const int maxn=505;
struct Point{double x,y;}p[maxn],a[maxn],S;
const double eps=1e-8;
int n,cnt,tot,h,t,tmp;
struct Line{Point s,t;double det;}L[maxn],q[maxn];
inline Point operator+(Point A,Point B) {return (Point){A.x+B.x,A.y+B.y};}
inline Point operator-(Point A,Point B) {return (Point){A.x-B.x,A.y-B.y};}
inline Point operator^(double g,Point C) {return (Point){C.x*g,C.y*g};}
inline double operator*(Point A,Point B) {return A.x*B.y-B.x*A.y;}
inline int dcmp(double A,double B) {return A+eps>B&&A-eps<B;}
inline int OnRight(const Point &a,const Line &c) {
	return (c.t-a)*(c.s-a)>0;
}
inline int cmp(const Line &A,const Line &B) {
	return dcmp(A.det,B.det)?OnRight(A.s,B):(A.det<B.det);
}
inline Point sec(const Line &A,const Line &B) {
	Point v1=A.t-A.s,v2=B.t-B.s,v3=A.s-B.s;
	double t=(v3*v2)/(v2*v1);
	return A.s+(t^v1);
}
int main() {
	scanf("%d",&n);S.x=1e18,S.y=1e18;
	for(re int m,i=1;i<=n;i++) {
		scanf("%d",&m);
		for(re int j=1;j<=m;j++) scanf("%lf%lf",&a[j].x,&a[j].y);
		for(re int j=1;j<m;++j) L[++cnt].s=a[j],L[cnt].t=a[j+1];
		L[++cnt].s=a[m],L[cnt].t=a[1];
	}
	for(re int i=1;i<=cnt;i++) 
		L[i].det=atan2((L[i].t-L[i].s).y,(L[i].t-L[i].s).x);
	std::sort(L+1,L+cnt+1,cmp);h=1,t=0;tot=0;
	for(re int i=1;i<=cnt;i++) {
		if(!dcmp(L[i].det,L[i-1].det)) ++tot;
		L[tot]=L[i];
	}
	q[++t]=L[1],q[++t]=L[2];
	for(re int i=3;i<=tot;i++) {
		while(h<t&&OnRight(sec(q[t],q[t-1]),L[i])) --t;
		while(h<t&&OnRight(sec(q[h],q[h+1]),L[i])) ++h;
		q[++t]=L[i];
	}
	while(h<t&&OnRight(sec(q[t],q[t-1]),q[h])) --t;
	while(h<t&&OnRight(sec(q[h],q[h+1]),q[t])) ++h;
	for(re int i=h;i<t;i++) p[++tmp]=sec(q[i],q[i+1]);p[++tmp]=sec(q[t],q[h]);
	double ans=p[tmp]*p[1];
	for(re int i=1;i<tmp;i++) ans+=p[i]*p[i+1];
	printf("%.3lf\n",ans*0.5);return 0;
}
posted @ 2020-01-07 07:56  asuldb  阅读(134)  评论(0编辑  收藏  举报