0% found this document useful (0 votes)
10 views13 pages

2021CCPC 桂林 F. Illuminations II (计算几何)

The document discusses a computational geometry problem involving intersections between an inner polygon and an outer polygon, suggesting the use of prefix sums for calculations. It includes a C++ code snippet that implements various mathematical functions and structures, such as points, lines, and circles, to facilitate geometric computations. The solution emphasizes efficiency and the avoidance of standard input methods during competitive programming.

Uploaded by

chenxia200062
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views13 pages

2021CCPC 桂林 F. Illuminations II (计算几何)

The document discusses a computational geometry problem involving intersections between an inner polygon and an outer polygon, suggesting the use of prefix sums for calculations. It includes a C++ code snippet that implements various mathematical functions and structures, such as points, lines, and circles, to facilitate geometric computations. The solution emphasizes efficiency and the avoidance of standard input methods during competitive programming.

Uploaded by

chenxia200062
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 13

[F. Illuminations II](https://codeforces.

com/gym/103409/problem/F)

![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/
508e03be97419ea4f7124482164d4333.png)

### Solution
内多边形每条线与外多边形做交点,利用前缀和计算即可。
还是挺容易想到的,比赛的时候没时间写了,写计算几何再也不用 cin 了。

### Code
```cpp
/*
/へ /|
/\7 ∠/
/ │ / /
│ | _,< / /`ヽ
│ ヽ / 〉
\ ` / /
● ⊃●
⊂ ⊂⊃〈 /
() へ | \〈
>ー 、_ ィ │ //
/ へ / ノ<| \\
ヽ_ノ (_/ │//
7 |/
>―= ̄ ̄`ー―_*/
#include <bits/stdc++.h>

using namespace std;


using ll = long long;

#define rep(i, a, b, stp) for(int i = a; i <= b; i += stp)


#define all(a) a.begin(), a.end()

namespace BASIC_MATH {
// const ll mod = 998244353, mod_g = 3, img = 86583718;
const ll mod = 19260817;
const double eps = 1e-6; // when use double gcd, let eps smaller(1e-4)
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int maxp = 100010;
// Very Basic
ll mul(ll a, ll b) { ll z = (long double) a / mod * b; ll res = (unsigned long
long) a * b - (unsigned long long) z * mod; return (res + mod) % mod; }
// O(1) quick_mul, use long double
inline ll quick_pow(ll ans, ll p, ll res = 1) {
for(; p; p >>= 1, ans = mul(ans, ans) % mod)
if(p & 1) res = mul(res, ans) % mod;
return res % mod;
}
double gcd(double a,double b) {
if(fabs(b) < eps) return a;
if(fabs(a) < eps) return b;
return gcd(b, fmod(a,b));
}
int gcd(int a, int b) { return __gcd(a, b); }
ll gcd(ll a, ll b) { return __gcd(a, b); }
// Exgcd
ll exgcd(ll A, ll B, ll &x, ll &y) { // Ax + By = C
if(B == 0) {x = 1; y = 0; return A; }
ll _gcd_ = exgcd(B, A % B, x, y);//逆推回去求解
ll t = x;
x = y; y = t - A / B * y;
return _gcd_;
}
void call_exgcd(ll A, ll B, ll C, ll &x, ll &y) {
ll d = exgcd(A, B, x, y);
if(C % d != 0) cout << -1 << '\n';
else { // k = 0 的通解
x = C / d * x;
y = C / d * y;
x %= mod; while(x < 0) x += mod;
y %= mod; while(y < 0) y += mod;
cout << x << ' ' << y << '\n';
}
}
// Geometry
int sgn(double x) { if(fabs(x) < eps) return 0; return x > 0? 1: -1; }
inline double sqr(double x) { return x * x; }
struct Point {
double x, y;
Point() { }
Point(double _x,double _y): x(_x), y(_y) { }
void input() { cin >> x >> y; }
void output() { cout << fixed << setprecision(12) << x << ' ' << y << '\n';
}
bool operator == (Point b)const { return sgn(x - b.x) == 0 && sgn(y - b.y)
== 0; }
bool operator < (Point b)const { return 1ll * x * b.y < y * b.x; }
Point operator -(const Point &b)const { return Point(x - b.x, y - b.y); }
double operator ^(const Point &b)const { return x * b.y - y * b.x; } // 叉乘
double operator *(const Point &b)const { return x * b.x + y * b.y; } // 点乘
double len() { return hypot(x, y); }
double len2() { return x * x + y * y; }
double distance(Point p) { return hypot(x - p.x, y - p.y); }
Point operator +(const Point &b)const { return Point(x + b.x, y + b.y); }
Point operator *(const double &k)const { return Point(x * k, y * k); }
Point operator /(const double &k)const { return Point(x / k, y / k); }
//`计算 pa 和 pb 的夹角`
double rad(Point a,Point b) { Point p = *this; return fabs(atan2( fabs((a -
p) ^ (b - p)), (a - p) * (b - p) )); }
//`化为长度为 r 的向量`
Point trunc(double r) { double l = len(); if(!sgn(l))return *this; r /= l;
return Point(x * r, y * r); }
//`逆时针旋转 90 度`
Point rotleft() { return Point(-y, x); }
//`顺时针旋转 90 度`
Point rotright() { return Point(y, -x); }
//`绕着 p 点逆时针旋转 angle`
Point rotate(Point p, double angle) {
Point v = (*this) - p; double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
};
struct Line {
Point s, e;
Line() { }
Line(Point _s, Point _e): s(_s), e(_e) { }
bool operator ==(Line v) { return (s == v.s) && (e == v.e); }
//`根据一个点和倾斜角 angle 确定直线, 0 <= angle < pi`
Line(Point p,double angle) {
s = p;
if(sgn(angle-pi/2) == 0) e = (s + Point(0, 1));
else e = (s + Point(1, tan(angle)));
}
//ax + by + c = 0
Line(double a,double b,double c) {
if(sgn(a) == 0) {
s = Point(0, -c / b);
e = Point(1, -c / b);
} else if(sgn(b) == 0) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
} else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
void input() { s.input(); e.input(); }
void adjust() { if(e < s) swap(s,e); }
double length() { return s.distance(e); }
//`倾斜角 0 <= angle < pi`
double angle() {
double k = atan2(e.y - s.y, e.x - s.x);
if(sgn(k) < 0)k += pi;
if(sgn(k - pi) == 0) k -= pi;
return k;
}
//`点和直线关系:`1 在左侧; 2 在右侧; 3 在直线上`
int relation(Point p) {
int c = sgn((p - s) ^ (e - s));
if(c < 0) return 1;
else if(c > 0) return 2;
else return 3;
}
// 点在线段上的判断
bool pointonseg(Point p) { return sgn((p - s) ^ (e - s)) == 0 && sgn((p -
s) * (p - e)) <= 0; }
//`直线平行或重合`
bool parallel(Line v) { return sgn((e - s) ^ (v.e - v.s)) == 0; }
//`两线段相交判断:`2 规范相交; 1 非规范相交; 0 不相交`
int segcrossseg(Line v) {
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int d4 = sgn((v.e-v.s)^(e-v.s));
if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
//`直线和线段相交判断:`2 规范相交; 1 非规范相交; 0 不相交`
int linecrossseg(Line v) {
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
if((d1 ^ d2) == -2) return 2;
return (d1 == 0 || d2 == 0);
}
//`两直线关系:`0 平行; 1 重合; 2 相交`
int linecrossline(Line v) {
if((*this).parallel(v))
return v.relation(s)==3;
return 2;
}
//`求两直线的交点``要保证两直线不平行或重合`
Point crosspoint(Line v) {
double a1 = (v.e-v.s)^(s-v.s);
double a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
//点到直线的距离
double dispointtoline(Point p) { return fabs((p-s)^(e-s))/length(); }
//点到线段的距离
double dispointtoseg(Point p) {
if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.distance(s),p.distance(e));
return dispointtoline(p);
}
//`返回线段到线段的距离``相交距离为 0`
double dissegtoseg(Line v) {
return
min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtos
eg(e)));
}
//`返回点 p 在直线上的投影`
Point lineprog(Point p) { return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2())
); }
//`返回点 p 关于直线的对称点`
Point symmetrypoint(Point p) { Point q = lineprog(p); return Point(2*q.x-
p.x,2*q.y-p.y); }
};
struct circle {
Point p; double r;
circle() { }
circle(Point _p, double _r): p(_p), r(_r) { }
circle(double x, double y, double _r) { p = Point(x,y); r = _r; }
//`三角形的外接圆``利用两条边的中垂线得到圆心`
circle(Point a, Point b, Point c) {
Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
p = u.crosspoint(v);
r = p.distance(a);
}
//`三角形的内切圆``参数 bool t 没有作用`
circle(Point a, Point b, Point c, bool t) {
Line u,v;
double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x);
u.s = a;
u.e = u.s + Point(cos((n+m)/2),sin((n+m)/2));
v.s = b;
m = atan2(a.y-b.y,a.x-b.x) , n = atan2(c.y-b.y,c.x-b.x);
v.e = v.s + Point(cos((n+m)/2),sin((n+m)/2));
p = u.crosspoint(v);
r = Line(a,b).dispointtoseg(p);
}
void input() { p.input(); cin >> r; }
void output() { cout << fixed << setprecision(9) << "x:" << p.x << ", y:"
<< p.y << ", r:" << r << '\n'; }
bool operator == (circle v) { return (p == v.p) && sgn(r - v.r) == 0; }
bool operator < (circle v)const { return ((p<v.p)||((p==v.p)&&sgn(r-
v.r)<0)); }
double area() { return pi * r * r; }
double circumference() { return 2 * pi * r; }
//`点和圆的关系: 0 圆外; 1 圆上; 2 圆内`
int relation(Point b) {
double dst = b.distance(p);
if(sgn(dst-r) < 0)return 2;
else if(sgn(dst-r)==0)return 1;
return 0;
}
//`线段和圆的关系``比较的是圆心到线段的距离和半径的关系`
int relationseg(Line v) {
double dst = v.dispointtoseg(p);
if(sgn(dst-r) < 0)return 2;
else if(sgn(dst-r) == 0)return 1;
return 0;
}
//`直线和圆的关系``比较的是圆心到直线的距离和半径的关系`
int relationline(Line v) {
double dst = v.dispointtoline(p);
if(sgn(dst-r) < 0)return 2;
else if(sgn(dst-r) == 0)return 1;
return 0;
}
//`两圆的关系: 5 相离; 4 外切; 3 相交; 2 内切; 1 内含`
int relationcircle(circle v) {
double d = p.distance(v.p);
if(sgn(d-r-v.r) > 0)return 5;
if(sgn(d-r-v.r) == 0)return 4;
double l = fabs(r-v.r);
if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3;
if(sgn(d-l)==0)return 2;
if(sgn(d-l)<0)return 1;
}
//`求两个圆的交点,返回 0 表示没有交点,返回 1 是一个交点,2 是两个交点`
int pointcrosscircle(circle v,Point &p1,Point &p2) {
int rel = relationcircle(v);
if(rel == 1 || rel == 5)return 0;
double d = p.distance(v.p);
double l = (d*d+r*r-v.r*v.r)/(2*d);
double h = sqrt(r*r-l*l);
Point tmp = p + (v.p-p).trunc(l);
p1 = tmp + ((v.p-p).rotleft().trunc(h));
p2 = tmp + ((v.p-p).rotright().trunc(h));
if(rel == 2 || rel == 4)
return 1;
return 2;
}
//`求直线和圆的交点,返回交点个数`
int pointcrossline(Line v,Point &p1,Point &p2) {
if(!(*this).relationline(v))return 0;
Point a = v.lineprog(p);
double d = v.dispointtoline(p);
d = sqrt(r*r-d*d);
if(sgn(d) == 0) {
p1 = a;
p2 = a;
return 1;
}
p1 = a + (v.e-v.s).trunc(d);
p2 = a - (v.e-v.s).trunc(d);
return 2;
}
//`得到过 a,b 两点,半径为 r1 的两个圆`
int gercircle(Point a,Point b,double r1,circle &c1,circle &c2) {
circle x(a,r1),y(b,r1);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r = c2.r = r1;
return t;
}
//`得到与直线 u 相切,过点 q,半径为 r1 的圆`
int getcircle(Line u,Point q,double r1,circle &c1,circle &c2) {
double dis = u.dispointtoline(q);
if(sgn(dis-r1*2)>0)return 0;
if(sgn(dis) == 0) {
c1.p = q + ((u.e-u.s).rotleft().trunc(r1));
c2.p = q + ((u.e-u.s).rotright().trunc(r1));
c1.r = c2.r = r1;
return 2;
}
Line u1 = Line((u.s + (u.e-u.s).rotleft().trunc(r1)),(u.e + (u.e-
u.s).rotleft().trunc(r1)));
Line u2 = Line((u.s + (u.e-u.s).rotright().trunc(r1)),(u.e + (u.e-
u.s).rotright().trunc(r1)));
circle cc = circle(q,r1);
Point p1,p2;
if(!cc.pointcrossline(u1,p1,p2))cc.pointcrossline(u2,p1,p2);
c1 = circle(p1,r1);
if(p1 == p2) {
c2 = c1;
return 1;
}
c2 = circle(p2,r1);
return 2;
}
//`同时与直线 u,v 相切,半径为 r1 的圆`
int getcircle(Line u,Line v,double r1,circle &c1,circle &c2,circle
&c3,circle &c4) {
if(u.parallel(v))return 0;//两直线平行
Line u1 = Line(u.s + (u.e-u.s).rotleft().trunc(r1),u.e + (u.e-
u.s).rotleft().trunc(r1));
Line u2 = Line(u.s + (u.e-u.s).rotright().trunc(r1),u.e + (u.e-
u.s).rotright().trunc(r1));
Line v1 = Line(v.s + (v.e-v.s).rotleft().trunc(r1),v.e + (v.e-
v.s).rotleft().trunc(r1));
Line v2 = Line(v.s + (v.e-v.s).rotright().trunc(r1),v.e + (v.e-
v.s).rotright().trunc(r1));
c1.r = c2.r = c3.r = c4.r = r1;
c1.p = u1.crosspoint(v1);
c2.p = u1.crosspoint(v2);
c3.p = u2.crosspoint(v1);
c4.p = u2.crosspoint(v2);
return 4;
}
//`同时与不相交圆 cx,cy 相切,半径为 r1 的圆`
int getcircle(circle cx,circle cy,double r1,circle &c1,circle &c2) {
circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
int t = x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r = c2.r = r1;
return t;
}
//`过一点作圆的切线(先判断点和圆的关系)`
int tangentline(Point q,Line &u,Line &v) {
int x = relation(q);
if(x == 2)return 0;
if(x == 1) {
u = Line(q,q + (q-p).rotleft());
v = u;
return 1;
}
double d = p.distance(q);
double l = r*r/d;
double h = sqrt(r*r-l*l);
u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h)));
v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h)));
return 2;
}
//`求两圆相交的面积`
double areacircle(circle v) {
int rel = relationcircle(v);
if(rel >= 4)return 0.0;
if(rel <= 2)return min(area(),v.area());
double d = p.distance(v.p);
double hf = (r+v.r+d)/2.0;
double ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
double a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
a1 = a1*r*r;
double a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
a2 = a2*v.r*v.r;
return a1+a2-ss;
}
//`求两圆相交的面积(精度更高)(需要 long double)`
double areacircle2(circle v) {
double a=hypot(p.x-v.p.x,p.y-v.p.y),b=r,c=v.r;
double s1=pi*r*r,s2=pi*v.r*v.r;
if(sgn(a-b-c)>=0)
return 0;
if(sgn(a+min(b,c)-max(b,c))<=0)
return min(s1,s2);
else {
double cta1=2*acos((a*a+b*b-c*c)/(2*a*b));
double cta2=2*acos((a*a+c*c-b*b)/(2*a*c));
return cta1/(2*pi)*s1-0.5*sin(cta1)*b*b+cta2/(2*pi)*s2-
0.5*sin(cta2)*c*c;
}
}
//`求圆和三角形 pab 的相交面积`
double areatriangle(Point a,Point b) {
if(sgn((p-a)^(p-b)) == 0)return 0.0;
Point q[5]; int len = 0;
q[len++] = a;
Line l(a,b); Point p1,p2;
if(pointcrossline(l,q[1],q[2])==2) {
if(sgn((a-q[1])*(b-q[1]))<0)q[len++] = q[1];
if(sgn((a-q[2])*(b-q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
double res = 0; for(int i = 0; i < len-1; i++) {
if(relation(q[i])==0||relation(q[i+1])==0) {
double arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
} else {
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
};
struct polygon {
int n; Point p[maxp]; Line l[maxp];
void input(int _n) { n = _n; for(int i = 0; i < n; i++) p[i].input(); }
void add(Point q) { p[n++] = q; }
void getline() { for(int i = 0; i < n; i++) l[i] = Line(p[i],p[(i + 1) %
n]); }
struct cmp {
Point p;
cmp(const Point &p0) { p = p0; }
bool operator()(const Point &aa,const Point &bb) {
Point a = aa, b = bb;
int d = sgn((a-p)^(b-p));
if(d == 0) {
return sgn(a.distance(p)-b.distance(p)) < 0;
}
return d > 0;
}
};
//`进行极角排序``首先需要找到最左下角的点`
void norm() { Point mi = p[0]; for(int i = 1; i < n; i++)mi = min(mi,p[i]);
sort(p,p+n,cmp(mi)); }
//`得到的凸包里面的点编号是 0~n-1``注意如果有影响,要特判下所有点共点,或者共线的特殊情况`
void getconvex(polygon &convex) {
sort(p,p + n); convex.n = n;
for(int i = 0; i < min(n,2); i++) convex.p[i] = p[i];
if(convex.n == 2 && (convex.p[0] == convex.p[1]))convex.n--;//特判
if(n <= 2)return; int &top = convex.n; top = 1;
for(int i = 2; i < n; i++) {
while(top && sgn((convex.p[top]-p[i])^(convex.p[top-1]-p[i])) <= 0)
top--;
convex.p[++top] = p[i];
}
int temp = top; convex.p[++top] = p[n-2];
for(int i = n-3; i >= 0; i--) {
while(top != temp && sgn((convex.p[top]-p[i])^(convex.p[top-1]-
p[i])) <= 0) top--;
convex.p[++top] = p[i];
}
if(convex.n == 2 && (convex.p[0] == convex.p[1])) convex.n--;
convex.norm();//`原来得到的是顺时针的点,排序后逆时针`
}
//`得到凸包的另外一种方法`
void Graham(polygon &convex) {
norm();
int &top = convex.n; top = 0;
if(n == 1) { top = 1; convex.p[0] = p[0]; return; }
if(n == 2) {
top = 2;
convex.p[0] = p[0];
convex.p[1] = p[1];
if(convex.p[0] == convex.p[1])top--;
return;
}
convex.p[0] = p[0]; convex.p[1] = p[1];
top = 2;
for(int i = 2; i < n; i++) {
while( top > 1 && sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-
convex.p[top-2])) <= 0 )
top--;
convex.p[top++] = p[i];
}
if(convex.n == 2 && (convex.p[0] == convex.p[1]))convex.n--;//特判
}
//`判断是不是凸的`
bool isconvex() {
bool s[3];
memset(s,false,sizeof(s));
for(int i = 0; i < n; i++) {
int j = (i+1)%n;
int k = (j+1)%n;
s[sgn((p[j]-p[i])^(p[k]-p[i]))+1] = true;
if(s[0] && s[2])return false;
}
return true;
}
//`判断点和任意多边形的关系`
//` 3 点上`
//` 2 边上`
//` 1 内部`
//` 0 外部`
int relationpoint(Point q) {
for(int i = 0; i < n; i++) {
if(p[i] == q)return 3;
}
getline();
for(int i = 0; i < n; i++) {
if(l[i].pointonseg(q))return 2;
}
int cnt = 0;
for(int i = 0; i < n; i++) {
int j = (i+1)%n;
int k = sgn((q-p[j])^(p[i]-p[j]));
int u = sgn(p[i].y-q.y);
int v = sgn(p[j].y-q.y);
if(k > 0 && u < 0 && v >= 0)cnt++;
if(k < 0 && v < 0 && u >= 0)cnt--;
}
return cnt != 0;
}
//`直线 u 切割凸多边形左侧`
//`注意直线方向`
//`测试:HDU3982`
void convexcut(Line u,polygon &po) {
int &top = po.n;//注意引用
top = 0;
for(int i = 0; i < n; i++) {
int d1 = sgn((u.e-u.s)^(p[i]-u.s));
int d2 = sgn((u.e-u.s)^(p[(i+1)%n]-u.s));
if(d1 >= 0)po.p[top++] = p[i];
if(d1*d2 < 0)po.p[top++] = u.crosspoint(Line(p[i],p[(i+1)%n]));
}
}
//`得到周长`
//`测试 LightOJ1239`
double getcircumference() {
double sum = 0;
for(int i = 0; i < n; i++) {
sum += p[i].distance(p[(i+1)%n]);
}
return sum;
}
//`得到面积`
double getarea() {
double sum = 0;
for(int i = 0; i < n; i++) {
sum += (p[i]^p[(i+1)%n]);
}
return fabs(sum)/2;
}
//`得到方向: 1 表示逆时针; 0 表示顺时针`
bool getdir() {
double sum = 0;
for(int i = 0; i < n; i++)
sum += (p[i]^p[(i+1)%n]);
if(sgn(sum) > 0)return 1;
return 0;
}
//`得到重心`
Point getbarycentre() {
Point ret(0,0);
double area = 0;
for(int i = 1; i < n-1; i++) {
double tmp = (p[i]-p[0])^(p[i+1]-p[0]);
if(sgn(tmp) == 0)continue;
area += tmp;
ret.x += (p[0].x+p[i].x+p[i+1].x)/3*tmp;
ret.y += (p[0].y+p[i].y+p[i+1].y)/3*tmp;
}
if(sgn(area)) ret = ret/area;
return ret;
}
//`多边形和圆交的面积`
double areacircle(circle c) {
double ans = 0;
for(int i = 0; i < n; i++) {
int j = (i+1)%n;
if(sgn( (p[j]-c.p)^(p[i]-c.p) ) >= 0)
ans += c.areatriangle(p[i],p[j]);
else ans -= c.areatriangle(p[i],p[j]);
}
return fabs(ans);
}
//`多边形和圆关系: 2 圆完全在多边形内; 1 圆在多边形里面,碰到了多边形边界; 0 其它`
int relationcircle(circle c) {
getline();
int x = 2;
if(relationpoint(c.p) != 1)return 0;//圆心不在内部
for(int i = 0; i < n; i++) {
if(c.relationseg(l[i])==2)return 0;
if(c.relationseg(l[i])==1)x = 1;
}
return x;
}
};
}
using namespace BASIC_MATH;

void solve() {
int n, m; scanf("%d%d", &n, &m);
vector<Point> outer(n), inner(m);
rep(i, 0, n - 1, 1) scanf("%lf%lf", &outer[i].x, &outer[i].y);
rep(i, 0, m - 1, 1) scanf("%lf%lf", &inner[i].x, &inner[i].y);

vector<Line> outer_line(n), inner_line(m);


vector<double> siz(n);
rep(i, 0, n - 1, 1) {
outer_line[i] = {outer[i], outer[(i + 1) % n]};
siz[i] += (i? siz[i - 1]: 0) + outer_line[i].length();
}
rep(i, 0, m - 1, 1) inner_line[i] = {inner[i], inner[(i + 1) % m]};

int f = 0, t = 0;
double ans = 0;

Point temp;

rep(i, 0, m - 1, 1) {
Point P(inner[i]), Q(inner[(i + 1) % m]);
Point cro1, cro2; Line l(P, Q);

while(1) {
if(l.linecrossseg(outer_line[f]) == 0) {
f = (f + 1) % n;
continue;
}
temp = l.crosspoint(outer_line[f]);
if(sgn(P.distance(temp) - Q.distance(temp)) < 0) {
f = (f + 1) % n;
continue;
}
break;
}
cro2 = l.crosspoint(outer_line[f]);

while(1) {
if(l.linecrossseg(outer_line[t]) == 0) {
t = (t + 1) % n;
continue;
}
temp = l.crosspoint(outer_line[t]);
if(sgn(P.distance(temp) - Q.distance(temp)) > 0) {
t = (t + 1) % n;
continue;
}
break;
}
cro1 = l.crosspoint(outer_line[t]);

int near_i = t, near_i_1 = f;

// cout << cro1.x << ' ' << cro1.y << '\n';
// cout << cro2.x << ' ' << cro2.y << '\n';

double len = cro2.distance(outer[near_i_1]) + cro1.distance(outer[(near_i +


1) % n]);

// cout << near_i << ' ' << near_i_1 << '\n';

if(near_i_1 < near_i) {


if(near_i_1 != 0) len += siz[(near_i_1 - 1 + n) % n];
len += (siz[n - 1] - siz[near_i]);
} else {
len += siz[(near_i_1 - 1 + n) % n] - siz[near_i];
}

// cout << len << '\n';

ans += l.length() * len;


}
printf("%.15f\n", ans / siz[n - 1]);
}

signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful!" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) /
CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
```

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy