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
",ans*0.5);return 0;
}