半平面交板子

卡精度是什么申必东西啊草

有别于我写凸包时的定义, * 表示点积, ^ 表示叉积。

排序增量法,将向量按极角排序后逐个加入队列,每次弹掉位于当前向量右边的交点。会发现这些交点在队列两侧,所以用双端队列维护。

用叉积求直线 \(P_1V_1\)\(P_2V_2\) 的交点 \(P_0\) : \(P_0=P_2+V_2\times(((P_2-P_1)^{\wedge} V_1)/(V_1^{\wedge} V_2))\)

注意弹直线时必须先弹队尾再弹队首。

具体用途包括但不限于:

  • 求多边形的核(多边形内能看到多边形所有位置的区域)

  • 求解形如 \(ax+by+z\leq 0\) 的不等式组

  • 求泰森多边形

  • 求多个一次函数在任意横坐标下的最值

等。

丢博就跑

洛谷P4169[模板]半平面交
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	#define int long long
	typedef double DB; typedef long long LL;
	int read(){
		int x=0,f=0; char ch=getchar();
		while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return f?-x:x;
	} char outp[50];
	void write(int x,char sp,int len=0){
		if(x<0) x=-x, putchar('-');
		do{ outp[len++]=x%10+'0', x/=10; }while(x);
		for(int i=len-1;~i;i--) putchar(outp[i]); putchar(sp);
	}
	void ckmax(int& x,int y){ x=x>y?x:y; }
	void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=50010;
const DB eps=1e-12;
int n;
DB ans;

namespace Geometry{
	#define pot vec
	struct vec{
		DB x,y;
		vec(){} vec(DB a,DB b){ x=a; y=b; }
		vec operator+(const vec& t)const{ return vec(x+t.x,y+t.y); }
		vec operator-(const vec& t)const{ return vec(x-t.x,y-t.y); }
		vec operator*(const DB& t)const{ return vec(x*t,y*t); }
		vec operator/(const DB& t)const{ return vec(x/t,y/t); }
		DB operator*(const vec& t)const{ return x*t.x+y*t.y; }
		DB operator^(const vec& t)const{ return x*t.y-y*t.x; }
	}p[NN];
	struct line{
		pot p; vec v; DB ang;
		line(){} line(pot a,pot b){ p=a; v=b-a; ang=atan2(v.y,v.x); }
		friend bool operator<(line a,line b){
			if(a.ang!=b.ang) return a.ang<b.ang;
			return ((b.p-a.p)^a.v)>0;
		}
	}l[NN],q[NN];
	int ql,qr,cnt;
	void read(vec& t){ scanf("%lf%lf",&t.x,&t.y); }
	bool left(line a,pot b){ return (a.v^(b-a.p))>0; }
	pot cross(line a,line b){
		pot p1=a.p,p2=b.p; vec v1=a.v,v2=b.v,u=p2-p1;
		return p2+v2*((u^v1)/(v1^v2));
	}
	void insersect(line* l,int cnt,int n=1){
		sort(l+1,l+cnt+1); q[ql=qr=1]=l[1];
		for(int i=2;i<=cnt;i++) if(l[i].ang!=l[i-1].ang) l[++n]=l[i];
		for(int i=2;i<=n;i++){
			while(ql<qr&&!left(l[i],p[qr-1])) --qr;
			while(ql<qr&&!left(l[i],p[ql  ])) ++ql;
			q[++qr]=l[i];
			if(ql<qr) p[qr-1]=cross(q[qr],q[qr-1]);
		}
		while(ql<qr&&!left(q[ql],p[qr-1])) --qr;
		if(ql<qr) p[qr]=cross(q[qr],q[ql]);
	}
} using namespace Geometry;


signed main(){
	n=read();
	for(int m,i=1;i<=n;i++){
		m=read();
		pot lst,tmp,st;
		for(int j=1;j<=m;j++){
			read(tmp);
			if(j^1) l[++cnt]=line(lst,tmp), lst=tmp;
			else st=lst=tmp;
		}
		l[++cnt]=line(lst,st);
	}
	insersect(l,cnt);
	for(int i=ql+1;i<qr;i++) ans+=(p[i]-p[ql])^(p[i+1]-p[ql]);
	printf("%.3lf\n",fabs(ans)/2);
	return 0;
}
posted @ 2022-02-09 15:43  keen_z  阅读(49)  评论(0编辑  收藏  举报