半平面交板子
卡精度是什么申必东西啊草
有别于我写凸包时的定义, *
表示点积, ^
表示叉积。
排序增量法,将向量按极角排序后逐个加入队列,每次弹掉位于当前向量右边的交点。会发现这些交点在队列两侧,所以用双端队列维护。
用叉积求直线 \(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;
}