【bzoj 2618】凸多边形(半平面交)

传送门biu~
把每个边看成一个向量,向量左边为指定区域。用向量求交点,用向量判断一个点是否在这条向量的左面。先在一个单调队列中不断加元素,最后再删队首队尾。注意细节

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-9;
struct point{
    double x,y;
    point(double _=0,double __=0){x=_;y=__;}
    point operator +(const point&r)const{return point(x+r.x,y+r.y);}
    point operator -(const point&r)const{return point(x-r.x,y-r.y);}
    double operator *(const point&r)const{return x*r.y-y*r.x;}
    point operator *(const double&r)const{return point(x*r,y*r);}
}p[55];
struct line{
    point p,v;
    double alpha;
    bool operator< (const line&r)const{return alpha<r.alpha;}
    line()  {}
    line(point a,point b){
        p=a;
        v=b-a;
        alpha=atan2(v.y,v.x);
    }
    point operator^ (const line&r) const{
        point re=p-r.p;
        double tmp=r.v*re/(v*r.v);//我把这写成了tmp=re*r.v/(v*r.v)就tmd调了一天 
        return p+v*tmp;
    }
}lines[550],stac[550];
int tp,head=1,tail;
bool onleft(point p,line l){
    point tmp=p-l.p;
    return l.v*tmp>=0;
}
void get_half_plane_intersection(){
    sort(lines+1,lines+tp+1);
    for(int i=1;i<=tp;++i){
        while(tail>=2 && !onleft(stac[tail]^stac[tail-1],lines[i])) --tail;
        if(tail>=1 && fabs(stac[tail].v*lines[i].v)<=eps){  //平行
            if(onleft(lines[i].p,stac[tail]))stac[tail]=lines[i];
        }
        else    stac[++tail]=lines[i];
    }
    while(1){
        if(tail-head+1>=2 && !onleft(stac[tail]^stac[tail-1],stac[head]))   --tail;
        else if(tail-head+1>=2 && !onleft(stac[head]^stac[head+1],stac[tail]))  ++head;
        else    break;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int m;
        scanf("%d",&m);
        for(int j=1;j<=m;++j){
            scanf("%lf%lf",&p[j].x,&p[j].y);
            if(j!=1)    lines[++tp]=line(p[j-1],p[j]);
        }
        lines[++tp]=line(p[m],p[1]);
    }
    get_half_plane_intersection();
    if(tail-head+1<=2)  printf("0.000");
    else{
        int sum=0;
        for(int i=head+1;i<=tail;++i)   p[++sum]=stac[i-1]^stac[i];
        p[++sum]=stac[tail]^stac[head];
        double ans=0;
        for(int i=2;i<=sum;++i) ans+=p[i-1]*p[i];
        ans+=p[sum]*p[1];
        printf("%.3lf",ans/2);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值