[模板] 半平面交

做法

考虑用射线(一个点和一个向量)表示它左侧的半平面

那么我们可以先按与x轴正半轴夹角(可用atan2(y,x)实现)排序,然后再用双端队列维护当前在交中的射线即可

之所以要用双端队列,是因为新插入一个半平面时队首和队尾都有可能被弹出,而且要注意的是,要先弹队尾再弹队首

在最后,还要再用队首的弹一些队尾的

例题

luogu4196 凸多边形
 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 #define MP make_pair
 5 #define fi first
 6 #define se second
 7 using namespace std;
 8 typedef long long ll;
 9 typedef unsigned long long ull;
10 typedef unsigned int ui;
11 typedef long double ld;
12 const int maxl=2333,maxn=12,maxm=55;
13 const ld eps=1e-9;
14 
15 inline char gc(){
16     return getchar();
17     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
18     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
19 }
20 inline ll rd(){
21     ll x=0;char c=gc();bool neg=0;
22     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
23     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
24     return neg?(~x+1):x;
25 }
26 
27 struct Node{
28     ld x,y;
29     Node(ld _x=0,ld _y=0){x=_x,y=_y;}
30 }p[maxn][maxm],it[maxl];
31 struct Line{
32     Node x,y;
33     Line(Node _x=0,Node _y=0){x=_x,y=_y;}
34 }l[maxl];
35 int N,M[maxn],cnt;
36 int hd,tl,q[maxl];
37 
38 inline ld operator ^(const Node a,const Node b){return a.x*b.y-a.y*b.x;}
39 inline Node operator +(const Node a,const Node b){return Node(a.x+b.x,a.y+b.y);}
40 inline Node operator -(const Node a,const Node b){return Node(a.x-b.x,a.y-b.y);}
41 inline Node operator *(const Node a,const ld b){return Node(a.x*b,a.y*b);}
42 inline ld myabs(const ld x){return x>0?x:-x;}
43 inline Node inter(const Line a,const Line b){
44     ld k1=(a.y-a.x)^(b.y-a.x),k2=(b.x-a.x)^(a.y-a.x);
45     return b.x+(b.y-b.x)*(k2/(k1+k2));
46 }
47 inline bool onright(const Line a,const Node b){return ((b-a.x)^(a.y-a.x))>=-eps;}
48 inline ld slope(Line a){return atan2((a.y-a.x).y,(a.y-a.x).x);}
49 
50 inline bool cmp(Line a,Line b){
51     ld x=slope(a),y=slope(b);
52     return (myabs(x-y)<eps)?(!onright(b,a.x)):(x<y);
53 }
54 
55 inline ld solve(){
56     sort(l+1,l+cnt+1,cmp);
57     hd=1,tl=0;
58     for(int i=1;i<=cnt;i++){
59         // printf("~%Lf %Lf\n",(l[i].y-l[i].x).x,(l[i].y-l[i].x).y);
60         if(i>1&&myabs(slope(l[i])-slope(l[i-1]))<eps) continue;
61         while(hd<tl&&onright(l[i],inter(l[q[tl]],l[q[tl-1]]))) tl--;
62         while(hd<tl&&onright(l[i],inter(l[q[hd]],l[q[hd+1]]))) hd++;
63         q[++tl]=i;
64     }
65     while(hd<tl&&onright(l[q[hd]],inter(l[q[tl]],l[q[tl-1]]))) tl--;
66     // while(hd<tl&&onright(l[q[tl]],inter(l[q[hd]],l[q[hd+1]]))) hd++;
67     // for(int i=hd;i<=tl;i++) printf("~%Lf %Lf %Lf %Lf\n",l[q[i]].x.x,l[q[i]].x.y,l[q[i]].y.x,l[q[i]].y.y);
68     if(hd+2>tl) return 0;
69     ld re=0;
70     q[tl+1]=q[hd];int n=0;
71     for(int i=hd;i<=tl;i++) it[++n]=inter(l[q[i]],l[q[i+1]]);
72     for(int i=2;i<n;i++) re+=myabs((it[i]-it[1])^(it[i+1]-it[1]));
73     return re/2;
74 }
75 
76 int main(){
77     //freopen("","r",stdin);
78     N=rd();
79     for(int i=1;i<=N;i++){
80         M[i]=rd();
81         for(int j=0;j<M[i];j++)
82             p[i][j].x=rd(),p[i][j].y=rd();
83         for(int j=0;j<M[i];j++){
84             l[++cnt]=Line(p[i][j],p[i][(j+1)%M[i]]);
85         }
86     }
87     printf("%.3Lf\n",solve());
88     return 0;
89 }

猜你喜欢

转载自www.cnblogs.com/Ressed/p/11055401.html