计算几何弱渣果然就是一点感觉也没有。
首先考虑不删怎么做?
肯定要把点给离散,那么现在对于每一小段,要求出是哪条线段最近?
按一个顺序扫过去,每一条线段打一个加入和删除的标记。
由于线段互不相交,所以线段顺序不会随着小段的移动而改变。
因此,我们可以用一个set去维护插入删除,比较远近时,就求交,判断谁近。
那么第一问答案就出来了。
第二问、第三问都是一样的。
删掉一条线段,对一小段来说,如果删掉了最近的那一条线段,答案会增加它和第二条线段的面积,那么维护v[i]表示删掉第i条线段面积增加多少,ans1=ans0+max(v[i])
第三问,首先答案是ans0+max(v[i])+cmax(v[i])
但是我们会发现我们少考虑了一种情况,那就是如果线段i和线段j是一小段的最近和次近,其实选择他们还会增加第二条线段到第三条线段的面积,随便做。
总复杂度是 O ( n l o g n ) O(n log n) O(nlogn)
注意用atan2(y,x)这个函数可以方便地做几角排序。
Code:
#include
#include
#include
#include
#define db double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 5e4 + 5;
int n;
const db eps = 1e-8;
struct P {
db x, y;
P(){}
P(db x_, db y_){x = x_, y = y_;}
} p, q;
struct L {
P p, v;
L(){}
L(P p_, P v_){p = p_, v = v_;}
};
P operator +(P a, P b) {return P(a.x + b.x, a.y + b.y);}
P operator -(P a, P b) {return P(a.x - b.x, a.y - b.y);}
P operator *(P a, db b) {return P(a.x * b, a.y * b);}
db operator ^(P a, P b) {return a.x * b.y - a.y * b.x;}
db dot(P a, P b) {return a.x * b.x + a.y * b.y;}
db len(P a) {return sqrt(dot(a, a));}
P jd(L a, L b) {return b.p + b.v * ((a.v ^ (a.p - b.p)) / (a.v ^ b.v));}
L a[N], ty, tz;
struct nod {
int x;
nod(int _x = 0) {x = _x;}
};
bool operator <(nod x, nod y) {
db u = len(jd(a[x.x], ty)), v = len(jd(a[y.x], ty));
if(abs(u - v) < eps) return x.x < y.x;
return u < v;
}
set<nod> s;
struct nod2 {
P p;
int x;
} d[N * 2]; int d0, D;
const db pi = acos(-1);
db jj(P p) {
return atan2(p.y, p.x);
}
int cmp2(nod2 a, nod2 b) {
return jj(a.p) < jj(b.p);
}
int c[N][2], c0[N];
struct edge {
int fi[N * 2], nt[N * 4], to[N * 4], v[N * 4], tot;
void link(int x, int y, int z) {
nt[++ tot] = fi[x], to[tot] = y, v[tot] = z, fi[x] = tot;
}
} e;
db ans0, ans1, ans2, v[N];
db calc(int x) {
return abs(jd(ty, a[x]) ^ jd(tz, a[x])) / 2;
}
struct nod3 {
int x, y; db z;
} w[N * 2]; int w0;
int cmp3(nod3 a, nod3 b) {
if(a.x < b.x) return 1;
if(a.x > b.x) return 0;
return a.y < b.y;
}
int main() {
freopen("area.in", "r", stdin);
freopen("area.out", "w", stdout);
scanf("%d", &n);
fo(i, 1, n) {
scanf("%lf %lf %lf %lf", &p.x, &p.y, &q.x, &q.y);
d[++ d0].p = p; d[d0].x = i;
d[++ d0].p = q; d[d0].x = i;
a[i].p = p; a[i].v = q - p;
}
{
sort(d + 1, d + d0 + 1, cmp2);
fo(i, 1, d0) {
if(i == 1 || abs(d[i].p ^ d[D].p) > eps) d[++ D] = d[i];
int x = d[i].x;
if(!c0[x]) c[x][c0[x] ++] = D; else {
c[x][1] = D;
if((d[c[x][0]].p ^ d[c[x][1]].p) < 0)
swap(c[x][0], c[x][1]);
}
}
}
fo(i, 1, n) {
if(c[i][0] < c[i][1])
e.link(c[i][1], i, -1), e.link(c[i][0], i, 1); else
e.link(c[i][1], i, -1), e.link(1, i, 1), e.link(c[i][0], i, 1);
}
fo(i, 1, D) {
ty.v = d[i].p; tz.v = d[i % D + 1].p;
for(int j = e.fi[i]; j; j = e.nt[j]) {
int x = e.to[j];
if(e.v[j] == 1) s.insert(nod(x)); else s.erase(s.find(nod(x)));
}
if(s.empty()) {
ans0 = ans1 = ans2 = 1e15;
} else {
int x = (*s.begin()).x;
ans0 += calc(x);
if(s.size() == 1) {
ans1 = ans2 = 1e15;
} else {
int y = (*++s.begin()).x;
v[x] += calc(y) - calc(x);
if(s.size() == 2) {
ans2 = 1e15;
} else {
int z = (*++(++s.begin())).x;
w[++ w0].x = x; w[w0].y = y;
w[w0].z = calc(z) - calc(y);
}
}
}
}
fo(i, 1, n) ans1 = max(ans1, ans0 + v[i]);
db c0 = 0, c1 = 0;
fo(i, 1, n) if(v[i] > c1)
c0 = c1, c1 = v[i]; else
if(v[i] > c0) c0 = v[i];
if(ans2 < 1e10) ans2 = ans0 + c0 + c1;
sort(w + 1, w + w0 + 1, cmp3);
fo(i, 2, w0 + 1) if(i > w0 || w[i - 1].x != w[i].x || w[i - 1].y != w[i].y) {
ans2 = max(ans2, ans0 + v[w[i - 1].x] + v[w[i - 1].y] + w[i - 1].z);
} else w[i].z += w[i - 1].z;
if(ans0 > 1e10) printf("infinite\n"); else printf("%.2lf\n", ans0);
if(ans1 > 1e10) printf("infinite\n"); else printf("%.2lf\n", ans1);
if(ans2 > 1e10) printf("infinite\n"); else printf("%.2lf\n", ans2);
}