列表

详情


NC13817. Find Quailty

描述

小Q同学失踪了!马上就要比赛了,但是何老师怎么也找不到小Q同学。现在何老师好不容易找到了一份地图,地图显示附近有一个凸多边形体育馆,但是由于现在是节假日,体育馆是关闭的,也就是说无法进入体育馆内部。
定位显示小Q同学最后一次出现在P位置,而现在距离小Q同学失踪已经过去了T个单位时间,在这段时间里小Q同学最多走T个单位距离,何老师希望你能帮他计算一下现在小Q同学可能出现的位置构成的区域的面积,这样何老师才能估计需要动用多少人力来寻找小Q同学。

输入描述

第一行是一个正整数T(≤ 1000),表示测试数据的组数, 对于每组测试数据, 第一行是一个整数n(3≤ n ≤ 100),表示凸多边形体育馆的顶点数, 接下来n行,每行是两个整数x_i,y_i(-1000 ≤ x_i,y_i ≤ 1000),按照逆时针的顺序给出体育馆的n个顶点, 最后一行是三个整数x_p,y_p,T(-1000 ≤ x_p,y_p ≤ 1000, 1 ≤ T ≤ 4000),表示位置P的坐标(保证不在多边形内,但可能在多边形的顶点或者边上)和小Q同学的失踪时间, 保证满足n>10的数据不超过100组。

输出描述

对于每组测试数据,输出由小Q同学现在可能出现的位置构成的区域的面积,要求相对误差不超过1e-6。 也就是说,令输出结果为a,标准答案为b,若满足fabs((a - b)/max(1.0, b))≤1e-6,则输出结果会被认为是正确答案。

示例1

输入:

2
4
0 0
2 0
2 2
0 2
3 1 1
4
0 0
2 0
2 2
0 2
3 1 3

输出:

3.141592653590
24.180805801865

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 219ms, 内存消耗: 672K, 提交时间: 2020-07-10 22:16:29

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>
  
using namespace std;
  
typedef long double db;
  
const db PI=acos(-1.0);
const db eps=1e-9;
  
inline int sgn(db x)
{
    return (x>eps ? 1 : (x<-eps ? -1 : 0));
}
  
struct Point
{
    db x,y;
    Point() {}
    Point(db _x,db _y):x(_x),y(_y) {}
    Point operator + (const Point &t)const
    {
        return Point(x+t.x,y+t.y);
    }
    Point operator - (const Point &t)const
    {
        return Point(x-t.x,y-t.y);
    }
    Point operator * (const db &t)const
    {
        return Point(x*t,y*t);
    }
    Point operator / (const db &t)const
    {
        return Point(x/t,y/t);
    }
    db operator * (const Point &t)const
    {
        return x*t.y-y*t.x;
    }
    db operator ^ (const Point &t)const
    {
        return x*t.x+y*t.y;
    }
    db len()const
    {
        return sqrt(x*x+y*y);
    }
    db arc(const int &on=0)const
    {
        db t=atan2(y,x);
        if(t<(on ? 1 : -1)*eps)t+=2*PI;
        return t;
    }
    db arc(const Point &t)const
    {
        db r=((*this)^t)/((*this).len()*t.len());
        return acos(max(-1.0L,min(1.0L,r)));
    }
    friend istream& operator >> (istream &in,Point &t)
    {
        in>>t.x>>t.y;
        return in;
    }
    friend ostream& operator << (ostream &out,const Point &t)
    {
        out<<"("<<t.x<<","<<t.y<<")";
        return out;
    }
};
  
struct Segment
{
    Point s,e;
    Segment() {}
    Segment(Point _s,Point _e):s(_s),e(_e) {}
    db get_ratio(const Point &t)const
    {
        return ((t-s)^(e-s))/((e-s)^(e-s));
    }
    Point get_point(const db &t)const
    {
        return s+(e-s)*t;
    }
    db cal_contribution(const db &a,const db &b)
    {
        return get_point(a)*get_point(b)/2;
    }
    bool on_segment(const Point &t)const
    {
        if(sgn((t-s)*(t-e)))return 0;
        db r=get_ratio(t);
        return sgn(r)>=0 && sgn(r-1)<=0;
    }
    vector<Point> operator & (const Segment &t)const
    {
        vector<Point> res;
        if(sgn((e-s)*(t.e-t.s))==0)
        {
            if(on_segment(t.s))res.push_back(t.s);
            if(on_segment(t.e))res.push_back(t.e);
            if(t.on_segment(s))res.push_back(s);
            if(t.on_segment(e))res.push_back(e);
            return res;
        }
        db r=((t.s-s)*(t.e-t.s))/((e-s)*(t.e-t.s));
        Point p=get_point(r);
        if(on_segment(p) && t.on_segment(p))
            res.push_back(p);
        return res;
    }
};
  
struct Circle
{
    Point o;
    db r,a,b;
    Circle() {}
    Circle(Point _o,db _r,db _a=0,db _b=2*PI):o(_o),r(_r),a(_a),b(_b) {}
    db get_arc(const Point &t)const
    {
        return (t-o).arc(a>eps);
    }
    bool in_circle(const Point &t,const int &cir=0,const int &lef=0,const int &rig=0)const
    {
        db d=(o-t).len();
        if(sgn(d-r)>=cir)return 0;
        if(sgn(d)==0)return 1;
        db s=get_arc(t);
        return sgn(s-a)>-lef && sgn(s-b)<rig;
    }
    bool on_circle(const Point &t)const
    {
        db d=(o-t).len();
        if(sgn(d-r))return 0;
        if(sgn(r)==0)return 1;
        db s=get_arc(t);
        return sgn(s-a)>=0 && sgn(s-b)<=0;
    }
    Point get_point(const db &t)const
    {
        return o+Point(cos(t),sin(t))*r;
    }
    db cal_contribution(const db &a,const db &b)const
    {
        return (get_point(a)*get_point(b)+r*r*((b-a)-sin(b-a)))/2;
    }
    db cal_area()const
    {
        return r*r*(b-a)/2;
    }
    vector<Point> operator & (const Segment &t)const
    {
        vector<Point> res;
        Point m=t.s+(t.e-t.s)*t.get_ratio(o);
        Point v=(t.e-t.s)/(t.e-t.s).len();
        db d=(m-o).len();
        if(sgn(d-r)>0)return res;
        d=sqrt(max(0.0L,r*r-d*d));
        for(int i=-1; i<=1; i+=2)
        {
            Point p=m+v*d*i;
            if(on_circle(p) && t.on_segment(p))
                res.push_back(p);
        }
        return res;
    }
    vector<Point> operator & (const Circle &t)const
    {
        vector<Point> res;
        db d=(o-t.o).len();
        if(sgn(d-fabs(r-t.r))<0 || sgn(d-(r+t.r))>0)return res;
        if(sgn(d)==0 && sgn(r-t.r)==0)
        {
            db p=max(a,t.a),q=min(b,t.b);
            if(sgn(p-q)<=0)
            {
                res.push_back(get_point(p));
                res.push_back(get_point(q));
            }
            return res;
        }
        db h=sqrt(max(0.0L,r*r-pow((r*r+d*d-t.r*t.r)/(2*d),2)));
        d=sqrt(max(0.0L,r*r-h*h));
        Point v=(t.o-o)/(t.o-o).len();
        Point m=o+v*d;
        v=Point(-v.y,v.x);
        for(int i=-1; i<=1; i+=2)
        {
            Point p=m+v*h*i;
            if(on_circle(p) && t.on_circle(p))
                res.push_back(p);
        }
        return res;
    }
    friend vector<Point> operator & (const Segment &lhs,const Circle &rhs)
    {
        return rhs&lhs;
    }
    friend istream& operator >> (istream &in,Circle &t)
    {
        in>>t.o>>t.r;
        t.a=0,t.b=2*PI;
        return in;
    }
};
  
struct Sector
{
    Circle c;
    Segment l,r;
    Sector() {}
    Sector(Circle _c)
    {
        c=_c;
        l=Segment(c.o,c.get_point(c.a));
        r=Segment(c.get_point(c.b),c.o);
    }
    db cal_area()const
    {
        return c.cal_area();
    }
    db operator & (const Sector &t)const
    {
        db res=0;
        if(sgn(c.r)==0 || sgn(t.c.r)==0)return res;
        Sector sec[2]= {*this,t};
        for(int i=0; i<2; i++)
        {
            vector<db> event;
            vector<Point> inter;
            Segment now[2]= {sec[i].l,sec[i].r};
            for(int j=0; j<2; j++)
            {
                event.clear();
                event.push_back(0),event.push_back(1);
                inter=now[j]&sec[i^1].l;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                inter=now[j]&sec[i^1].r;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                inter=now[j]&sec[i^1].c;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                sort(event.begin(),event.end());
                for(int k=0; k+1<(int)event.size(); k++)
                    if(sec[i^1].c.in_circle(now[j].get_point((event[k]+event[k+1])/2),i,i,i^1))
                        res+=now[j].cal_contribution(event[k],event[k+1]);
            }
            {
                event.clear();
                event.push_back(sec[i].c.a),event.push_back(sec[i].c.b);
                inter=sec[i].c&sec[i^1].l;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                inter=sec[i].c&sec[i^1].r;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                inter=sec[i].c&sec[i^1].c;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                sort(event.begin(),event.end());
                for(int k=0; k+1<(int)event.size(); k++)
                    if(sec[i^1].c.in_circle(sec[i].c.get_point((event[k]+event[k+1])/2),i,i,i^1))
                        res+=sec[i].c.cal_contribution(event[k],event[k+1]);
            }
        }
        return res;
    }
};
  
vector<int> get_tangent(vector<Point> polygon,Point location)
{
    int n=(int)polygon.size();
    vector<int> res(2);
    for(int i=0; i<2; i++)
        res[i]=(sgn(location.x-polygon[0].x)==0 && sgn(location.y-polygon[0].y)==0);
    for(int i=0; i<2*n; i++)
    {
        int id=i%n;
        if(sgn((polygon[id]-location)*(polygon[res[0]]-location))<0)res[0]=id;
        if(sgn((polygon[id]-location)*(polygon[res[1]]-location))>0)res[1]=id;
    }
    return res;
}
  
vector<vector<Point> > split_polygon(vector<Point> polygon,Point location)
{
    int n=(int)polygon.size();
    vector<int> cut=get_tangent(polygon,location);
    vector<Point> first,second;
    for(int i=cut[1];; i=(i+1)%n)
    {
        first.push_back(polygon[i]);
        if(i==cut[0])break;
    }
    for(int i=cut[0];; i=(i+1)%n)
    {
        second.push_back(polygon[i]);
        if(i==cut[1])break;
    }
    first.push_back(location);
    second.push_back(location);
    reverse(second.begin(),second.end());
    return vector<vector<Point> > {first,second};
}
  
db get_intersection(vector<Point> polygon,Circle cover)
{
    int n=(int)polygon.size();
    db res=0;
    for(int i=0; i<n; i++)
    {
        Point a=polygon[i];
        Point b=polygon[(i+1)%n];
        vector<Point> tmp=Segment(a,b)&cover;
        tmp.insert(tmp.begin(),a);
        tmp.push_back(b);
        for(int j=0; j+1<(int)tmp.size(); j++)
        {
            if(cover.in_circle((tmp[j]+tmp[j+1])/2))
                res+=(tmp[j]-cover.o)*(tmp[j+1]-cover.o);
            else
            {
                db t=(tmp[j]-cover.o).arc(tmp[j+1]-cover.o);
                res+=cover.r*cover.r*t*sgn((tmp[j]-cover.o)*(tmp[j+1]-cover.o));
            }
        }
    }
    return res/2;
}
  
void add_sector(vector<Sector> &sectors,Circle now)
{
    if(sgn(now.a-now.b)<=0)sectors.push_back(Sector(now));
    else
    {
        sectors.push_back(Sector(Circle(now.o,now.r,now.a,2*PI)));
        sectors.push_back(Sector(Circle(now.o,now.r,0,now.b)));
    }
}
  
db sum_of_sectors(vector<Point> polygon,db distance)
{
    polygon.insert(polygon.begin(),polygon.back());
    int n=(int)polygon.size();
    vector<Sector> lef,rig;
    add_sector(lef,Circle(polygon[0],distance,(polygon[n-2]-polygon[n-1]).arc(),(polygon[1]-polygon[0]).arc()));
    add_sector(rig,Circle(polygon[0],distance,(polygon[n-2]-polygon[n-1]).arc(),(polygon[1]-polygon[0]).arc()));
    db lef_len=max(0.0L,distance-(polygon[1]-polygon[0]).len()),rig_len=max(0.0L,distance-(polygon[n-2]-polygon[n-1]).len());
    int lef_pos=1,rig_pos=n-2;
    while(lef_pos+1<rig_pos)
    {
        if(lef_len>rig_len)
        {
            add_sector(lef,Circle(polygon[lef_pos],lef_len,(polygon[lef_pos]-polygon[lef_pos-1]).arc(),(polygon[lef_pos+1]-polygon[lef_pos]).arc()));
            lef_len=max(0.0L,lef_len-(polygon[lef_pos+1]-polygon[lef_pos]).len()),lef_pos++;
        }
        else
        {
            add_sector(rig,Circle(polygon[rig_pos],rig_len,(polygon[rig_pos-1]-polygon[rig_pos]).arc(),(polygon[rig_pos]-polygon[rig_pos+1]).arc()));
            rig_len=max(0.0L,rig_len-(polygon[rig_pos-1]-polygon[rig_pos]).len()),rig_pos--;
        }
    }
    add_sector(lef,Circle(polygon[lef_pos],lef_len,(polygon[lef_pos]-polygon[lef_pos-1]).arc(),(polygon[lef_pos+1]-polygon[lef_pos]).arc()));
    add_sector(rig,Circle(polygon[rig_pos],rig_len,(polygon[rig_pos-1]-polygon[rig_pos]).arc(),(polygon[rig_pos]-polygon[rig_pos+1]).arc()));
    db res=0;
    for(int i=0; i<(int)lef.size(); i++)
        res+=lef[i].cal_area();
    for(int i=0; i<(int)rig.size(); i++)
        res+=rig[i].cal_area();
    for(int i=0; i<(int)lef.size(); i++)
        for(int j=0; j<(int)rig.size(); j++)
            res-=lef[i]&rig[j];
    return res;
}
  
db solve(vector<Point> polygon,Circle cover)
{
    vector<vector<Point> > tmp=split_polygon(polygon,cover.o);
    return get_intersection(tmp[1],cover)+sum_of_sectors(tmp[0],cover.r);
}
  
int cnt=0;
void Main()
{
    cnt++;
    int n;
    cin>>n;
    vector<Point> polygon(n);
    for(int i=0; i<n; i++)
        cin>>polygon[i];
    Circle cover;
    cin>>cover;
    cout<<solve(polygon,cover)<<endl;
}
  
int main()
{
    int T;
    cin>>T;
    cout<<fixed<<setprecision(12);
    while(T--)Main();
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 273ms, 内存消耗: 500K, 提交时间: 2017-09-06 13:55:46

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<iomanip>
#include<algorithm>

using namespace std;

typedef long double db;

const db PI=acos(-1.0);
const db eps=1e-9;

inline int sgn(db x)
{
    return (x>eps ? 1 : (x<-eps ? -1 : 0));
}

struct Point
{
    db x,y;
    Point() {}
    Point(db _x,db _y):x(_x),y(_y) {}
    Point operator + (const Point &t)const
    {
        return Point(x+t.x,y+t.y);
    }
    Point operator - (const Point &t)const
    {
        return Point(x-t.x,y-t.y);
    }
    Point operator * (const db &t)const
    {
        return Point(x*t,y*t);
    }
    Point operator / (const db &t)const
    {
        return Point(x/t,y/t);
    }
    db operator * (const Point &t)const
    {
        return x*t.y-y*t.x;
    }
    db operator ^ (const Point &t)const
    {
        return x*t.x+y*t.y;
    }
    db len()const
    {
        return sqrt(x*x+y*y);
    }
    db arc(const int &on=0)const
    {
        db t=atan2(y,x);
        if(t<(on ? 1 : -1)*eps)t+=2*PI;
        return t;
    }
    db arc(const Point &t)const
    {
        db r=((*this)^t)/((*this).len()*t.len());
        return acos(max(-1.0L,min(1.0L,r)));
    }
    friend istream& operator >> (istream &in,Point &t)
    {
        in>>t.x>>t.y;
        return in;
    }
    friend ostream& operator << (ostream &out,const Point &t)
    {
        out<<"("<<t.x<<","<<t.y<<")";
        return out;
    }
};

struct Segment
{
    Point s,e;
    Segment() {}
    Segment(Point _s,Point _e):s(_s),e(_e) {}
    db get_ratio(const Point &t)const
    {
        return ((t-s)^(e-s))/((e-s)^(e-s));
    }
    Point get_point(const db &t)const
    {
        return s+(e-s)*t;
    }
    db cal_contribution(const db &a,const db &b)
    {
        return get_point(a)*get_point(b)/2;
    }
    bool on_segment(const Point &t)const
    {
        if(sgn((t-s)*(t-e)))return 0;
        db r=get_ratio(t);
        return sgn(r)>=0 && sgn(r-1)<=0;
    }
    vector<Point> operator & (const Segment &t)const
    {
        vector<Point> res;
        if(sgn((e-s)*(t.e-t.s))==0)
        {
            if(on_segment(t.s))res.push_back(t.s);
            if(on_segment(t.e))res.push_back(t.e);
            if(t.on_segment(s))res.push_back(s);
            if(t.on_segment(e))res.push_back(e);
            return res;
        }
        db r=((t.s-s)*(t.e-t.s))/((e-s)*(t.e-t.s));
        Point p=get_point(r);
        if(on_segment(p) && t.on_segment(p))
            res.push_back(p);
        return res;
    }
};

struct Circle
{
    Point o;
    db r,a,b;
    Circle() {}
    Circle(Point _o,db _r,db _a=0,db _b=2*PI):o(_o),r(_r),a(_a),b(_b) {}
    db get_arc(const Point &t)const
    {
        return (t-o).arc(a>eps);
    }
    bool in_circle(const Point &t,const int &cir=0,const int &lef=0,const int &rig=0)const
    {
        db d=(o-t).len();
        if(sgn(d-r)>=cir)return 0;
        if(sgn(d)==0)return 1;
        db s=get_arc(t);
        return sgn(s-a)>-lef && sgn(s-b)<rig;
    }
    bool on_circle(const Point &t)const
    {
        db d=(o-t).len();
        if(sgn(d-r))return 0;
        if(sgn(r)==0)return 1;
        db s=get_arc(t);
        return sgn(s-a)>=0 && sgn(s-b)<=0;
    }
    Point get_point(const db &t)const
    {
        return o+Point(cos(t),sin(t))*r;
    }
    db cal_contribution(const db &a,const db &b)const
    {
        return (get_point(a)*get_point(b)+r*r*((b-a)-sin(b-a)))/2;
    }
    db cal_area()const
    {
        return r*r*(b-a)/2;
    }
    vector<Point> operator & (const Segment &t)const
    {
        vector<Point> res;
        Point m=t.s+(t.e-t.s)*t.get_ratio(o);
        Point v=(t.e-t.s)/(t.e-t.s).len();
        db d=(m-o).len();
        if(sgn(d-r)>0)return res;
        d=sqrt(max(0.0L,r*r-d*d));
        for(int i=-1; i<=1; i+=2)
        {
            Point p=m+v*d*i;
            if(on_circle(p) && t.on_segment(p))
                res.push_back(p);
        }
        return res;
    }
    vector<Point> operator & (const Circle &t)const
    {
        vector<Point> res;
        db d=(o-t.o).len();
        if(sgn(d-fabs(r-t.r))<0 || sgn(d-(r+t.r))>0)return res;
        if(sgn(d)==0 && sgn(r-t.r)==0)
        {
            db p=max(a,t.a),q=min(b,t.b);
            if(sgn(p-q)<=0)
            {
                res.push_back(get_point(p));
                res.push_back(get_point(q));
            }
            return res;
        }
        db h=sqrt(max(0.0L,r*r-pow((r*r+d*d-t.r*t.r)/(2*d),2)));
        d=sqrt(max(0.0L,r*r-h*h));
        Point v=(t.o-o)/(t.o-o).len();
        Point m=o+v*d;
        v=Point(-v.y,v.x);
        for(int i=-1; i<=1; i+=2)
        {
            Point p=m+v*h*i;
            if(on_circle(p) && t.on_circle(p))
                res.push_back(p);
        }
        return res;
    }
    friend vector<Point> operator & (const Segment &lhs,const Circle &rhs)
    {
        return rhs&lhs;
    }
    friend istream& operator >> (istream &in,Circle &t)
    {
        in>>t.o>>t.r;
        t.a=0,t.b=2*PI;
        return in;
    }
};

struct Sector
{
    Circle c;
    Segment l,r;
    Sector() {}
    Sector(Circle _c)
    {
        c=_c;
        l=Segment(c.o,c.get_point(c.a));
        r=Segment(c.get_point(c.b),c.o);
    }
    db cal_area()const
    {
        return c.cal_area();
    }
    db operator & (const Sector &t)const
    {
        db res=0;
        if(sgn(c.r)==0 || sgn(t.c.r)==0)return res;
        Sector sec[2]= {*this,t};
        for(int i=0; i<2; i++)
        {
            vector<db> event;
            vector<Point> inter;
            Segment now[2]= {sec[i].l,sec[i].r};
            for(int j=0; j<2; j++)
            {
                event.clear();
                event.push_back(0),event.push_back(1);
                inter=now[j]&sec[i^1].l;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                inter=now[j]&sec[i^1].r;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                inter=now[j]&sec[i^1].c;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(now[j].get_ratio(inter[k]));
                sort(event.begin(),event.end());
                for(int k=0; k+1<(int)event.size(); k++)
                    if(sec[i^1].c.in_circle(now[j].get_point((event[k]+event[k+1])/2),i,i,i^1))
                        res+=now[j].cal_contribution(event[k],event[k+1]);
            }
            {
                event.clear();
                event.push_back(sec[i].c.a),event.push_back(sec[i].c.b);
                inter=sec[i].c&sec[i^1].l;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                inter=sec[i].c&sec[i^1].r;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                inter=sec[i].c&sec[i^1].c;
                for(int k=0; k<(int)inter.size(); k++)
                    event.push_back(sec[i].c.get_arc(inter[k]));
                sort(event.begin(),event.end());
                for(int k=0; k+1<(int)event.size(); k++)
                    if(sec[i^1].c.in_circle(sec[i].c.get_point((event[k]+event[k+1])/2),i,i,i^1))
                        res+=sec[i].c.cal_contribution(event[k],event[k+1]);
            }
        }
        return res;
    }
};

vector<int> get_tangent(vector<Point> polygon,Point location)
{
    int n=(int)polygon.size();
    vector<int> res(2);
    for(int i=0; i<2; i++)
        res[i]=(sgn(location.x-polygon[0].x)==0 && sgn(location.y-polygon[0].y)==0);
    for(int i=0; i<2*n; i++)
    {
        int id=i%n;
        if(sgn((polygon[id]-location)*(polygon[res[0]]-location))<0)res[0]=id;
        if(sgn((polygon[id]-location)*(polygon[res[1]]-location))>0)res[1]=id;
    }
    return res;
}

vector<vector<Point> > split_polygon(vector<Point> polygon,Point location)
{
    int n=(int)polygon.size();
    vector<int> cut=get_tangent(polygon,location);
    vector<Point> first,second;
    for(int i=cut[1];; i=(i+1)%n)
    {
        first.push_back(polygon[i]);
        if(i==cut[0])break;
    }
    for(int i=cut[0];; i=(i+1)%n)
    {
        second.push_back(polygon[i]);
        if(i==cut[1])break;
    }
    first.push_back(location);
    second.push_back(location);
    reverse(second.begin(),second.end());
    return vector<vector<Point> > {first,second};
}

db get_intersection(vector<Point> polygon,Circle cover)
{
    int n=(int)polygon.size();
    db res=0;
    for(int i=0; i<n; i++)
    {
        Point a=polygon[i];
        Point b=polygon[(i+1)%n];
        vector<Point> tmp=Segment(a,b)&cover;
        tmp.insert(tmp.begin(),a);
        tmp.push_back(b);
        for(int j=0; j+1<(int)tmp.size(); j++)
        {
            if(cover.in_circle((tmp[j]+tmp[j+1])/2))
                res+=(tmp[j]-cover.o)*(tmp[j+1]-cover.o);
            else
            {
                db t=(tmp[j]-cover.o).arc(tmp[j+1]-cover.o);
                res+=cover.r*cover.r*t*sgn((tmp[j]-cover.o)*(tmp[j+1]-cover.o));
            }
        }
    }
    return res/2;
}

void add_sector(vector<Sector> &sectors,Circle now)
{
    if(sgn(now.a-now.b)<=0)sectors.push_back(Sector(now));
    else
    {
        sectors.push_back(Sector(Circle(now.o,now.r,now.a,2*PI)));
        sectors.push_back(Sector(Circle(now.o,now.r,0,now.b)));
    }
}

db sum_of_sectors(vector<Point> polygon,db distance)
{
    polygon.insert(polygon.begin(),polygon.back());
    int n=(int)polygon.size();
    vector<Sector> lef,rig;
    add_sector(lef,Circle(polygon[0],distance,(polygon[n-2]-polygon[n-1]).arc(),(polygon[1]-polygon[0]).arc()));
    add_sector(rig,Circle(polygon[0],distance,(polygon[n-2]-polygon[n-1]).arc(),(polygon[1]-polygon[0]).arc()));
    db lef_len=max(0.0L,distance-(polygon[1]-polygon[0]).len()),rig_len=max(0.0L,distance-(polygon[n-2]-polygon[n-1]).len());
    int lef_pos=1,rig_pos=n-2;
    while(lef_pos+1<rig_pos)
    {
        if(lef_len>rig_len)
        {
            add_sector(lef,Circle(polygon[lef_pos],lef_len,(polygon[lef_pos]-polygon[lef_pos-1]).arc(),(polygon[lef_pos+1]-polygon[lef_pos]).arc()));
            lef_len=max(0.0L,lef_len-(polygon[lef_pos+1]-polygon[lef_pos]).len()),lef_pos++;
        }
        else
        {
            add_sector(rig,Circle(polygon[rig_pos],rig_len,(polygon[rig_pos-1]-polygon[rig_pos]).arc(),(polygon[rig_pos]-polygon[rig_pos+1]).arc()));
            rig_len=max(0.0L,rig_len-(polygon[rig_pos-1]-polygon[rig_pos]).len()),rig_pos--;
        }
    }
    add_sector(lef,Circle(polygon[lef_pos],lef_len,(polygon[lef_pos]-polygon[lef_pos-1]).arc(),(polygon[lef_pos+1]-polygon[lef_pos]).arc()));
    add_sector(rig,Circle(polygon[rig_pos],rig_len,(polygon[rig_pos-1]-polygon[rig_pos]).arc(),(polygon[rig_pos]-polygon[rig_pos+1]).arc()));
    db res=0;
    for(int i=0; i<(int)lef.size(); i++)
        res+=lef[i].cal_area();
    for(int i=0; i<(int)rig.size(); i++)
        res+=rig[i].cal_area();
    for(int i=0; i<(int)lef.size(); i++)
        for(int j=0; j<(int)rig.size(); j++)
            res-=lef[i]&rig[j];
    return res;
}

db solve(vector<Point> polygon,Circle cover)
{
    vector<vector<Point> > tmp=split_polygon(polygon,cover.o);
    return get_intersection(tmp[1],cover)+sum_of_sectors(tmp[0],cover.r);
}

int cnt=0;
void Main()
{
    cnt++;
    int n;
    cin>>n;
    vector<Point> polygon(n);
    for(int i=0; i<n; i++)
        cin>>polygon[i];
    Circle cover;
    cin>>cover;
    cout<<solve(polygon,cover)<<endl;
}

int main()
{
    int T;
    cin>>T;
    cout<<fixed<<setprecision(12);
    while(T--)Main();
    return 0;
}

上一题