以前写的代码,怕以后找不到了,放在这里安全点。
其实没太多的技术含量,用平衡树维护,配合链表,利用增量算法的思想,注意细节,使劲写就行了。
动态维护半平面交
# include <cstdlib> # include <cstdio> # include <cmath> # include <cstring> using namespace std; const int maxn = 100000+ 20; const double eps = 1e-6; double sx, sy; int prev[maxn], next[maxn]; double a[maxn]; int n, tot, root, aux[maxn], link[maxn][2]; struct line { double a, b, c, k; void reverse() { a = -a, b = -b, c = -c; } }lin[maxn]; struct point { double x, y, z; }lp[maxn], rp[maxn]; inline bool bezero(double x) { return x < eps && x > -eps ? true: false; } inline bool stayout(line u, point v) { return u.a*v.x + u.b*v.y + u.c*v.z < -eps ? true:false; } point get_point(line u, line v) { point g; g.x = u.b*v.c - u.c*v.b; g.y = u.c*v.a - u.a*v.c; g.z = u.a*v.b - u.b*v.a; if (!bezero(g.z)) g.x /= g.z, g.y /= g.z, g.z = 1; return g; } inline double cross(point u, point v) { return u.x*v.y - u.y*v.x; } void updata(int i) { a[i] = a[link[i][0]] + a[link[i][1]] + cross(lp[i], rp[i]); } void rotate(int &i, int p) { int j = link[i][p]; link[i][p] =link[j][!p]; link[j][!p] = i; updata(i);updata(j); i = j; } void insert(int &i, int x) { if (i == 0) i = x, aux[i] = rand() << 10 + rand(); else { int p = (lin[x].k > lin[i].k-eps); insert(link[i][p], x); if (aux[i] < aux[link[i][p]]) rotate(i, p); } } void cancel(int &i, int x) { if (i == x) if (link[i][0] && link[i][1]) { int p = aux[link[i][1]] > aux[link[i][0]]; rotate(i, p); cancel(link[i][!p], x); } else i = link[i][link[i][1]!= 0]; else cancel(link[i][lin[x].k > lin[i].k-eps], x); } void updata(int i, int j) { if (i != j) { if (lin[j].k-lin[i].k <-eps ) updata(link[i][0], j); else updata(link[i][1], j); } updata(i); } void findpred(int i, int x, int &l) { if (!i) return ; if (lin[x].k > lin[i].k-eps) l = i, findpred(link[i][1], x, l); else findpred(link[i][0], x, l); } int findlast(int i) { return link[i][1] == 0? i: findlast(link[i][1]); } void remove(int x) { prev[next[x]] = prev[x]; next[prev[x]] = next[x]; } void make_line(double x1, double y1, double x2, double y2) { tot++; double z1 = 1,z2 = 1; lin[tot].a = y1*z2 - y2*z1; lin[tot].b = z1*x2 - z2*x1; lin[tot].c = x1*y2 - x2*y1; lin[tot].k = atan2(x2-x1, y1-y2); point g = (point){x1+y1-y2, y1+x2-x1,1}; if (stayout(lin[tot], g)) lin[tot].reverse(); } void prepare() { int i; lin[1] = (line){0,-1,sy, atan2(-1,0)}; lin[2] = (line){1,0,0, atan2(0,1)}; lin[3] = (line){0,1,0, atan2(1,0)}; lin[4] = (line){-1,0,sx,atan2(0,-1)}; prev[1] = 4; next[1] = 2; prev[2] = 1; next[2] = 3; prev[3] = 2; next[3] = 4; prev[4] = 3; next[4] = 1; for (i =1; i <= 4; i++) { lp[i] = get_point(lin[i], lin[prev[i]]), rp[i] = get_point(lin[i], lin[next[i]]); insert(root, i); updata(root, i); } tot = 4; } int main() { int i; double x1, y1, x2, y2; int l, r; freopen("h.in", "r", stdin); freopen("h.out", "w", stdout); scanf("%d%lf%lf", &n, &sx, &sy); prepare(); for (i = 1; i <= n; i++) { scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); make_line(x1, y1, x2, y2); l = 0;findpred(root, tot, l); if (l == 0) l = findlast(root); r = next[l]; if ( stayout(lin[tot], lp[r])) { for (;stayout(lin[tot], lp[l]);) cancel(root, l), remove(l), l = prev[l]; for (;stayout(lin[tot], rp[r]);) cancel(root, r), remove(r), r = next[r]; insert(root, tot); lp[tot] = get_point(lin[tot], lin[l]); rp[tot] = get_point(lin[tot], lin[r]); rp[l] = lp[tot]; lp[r] =rp[tot]; next[l] = tot; prev[tot] = l; next[tot] = r; prev[r] = tot; updata(root, tot); updata(root, l); updata(root, r); } printf("%.4lf\n", a[root]*0.5); } return 0; }
动态维护凸包:
include <cstdlib> # include <cstdio> # include <cstring> # include <cmath> # include <ctime> using namespace std; const double eps = 1e-6; const int maxn = 200000; int link[maxn][2], prev[maxn], next[maxn], te[maxn], aux[maxn]; long long area[maxn], ans; int butler, root, tot, n; struct point { long long x, y; double k; void read() { scanf("%I64d%I64d", &x, &y); x*= 3; y*= 3; } void make(point base) { long long dx = x - base.x, dy = y - base.y; k = atan2(dy, dx)*1e3; } }base,d[maxn]; long long cross(int u, int v) { return 1LL* d[u].x*d[v].y-1LL*d[u].y*d[v].x; } long long cross2(int a, int b, int c, int e) { long long x1=d[b].x-d[a].x, y1=d[b].y-d[a].y, x2=d[e].x-d[c].x, y2=d[e].y-d[c].y; return 1LL*x1*y2 - 1LL*x2*y1; } void rotate(int &i, int p) { int j = link[i][p]; link[i][p] = link[j][!p]; link[j][!p] = i; i = j; } void insert(int &i, int x) { int p; if (i == 0) te[i = ++butler] = x, aux[i] = rand()<<15+rand(); else { if (d[x].k - d[te[i]].k < -eps) p = 0; else p = 1; insert(link[i][p], x); if (aux[i] < aux[link[i][p]]) rotate(i, p); } } void prepare() { int i, j; point tmp; d[1].read(); d[2].read(); d[3].read(); base.x = (d[1].x+d[2].x+d[3].x)/3; base.y = (d[1].y+d[2].y+d[3].y)/3; d[1].make(base); d[2].make(base); d[3].make(base); for (i = 1; i <= 3; i++) for (j = i+1; j <= 3; j++) if (d[i].k > d[j].k) tmp = d[i], d[i] = d[j], d[j] = tmp; prev[1] = 3; next[1] = 2; area[1] = cross(3, 1); insert(root, 1); prev[2] = 1; next[2] = 3; area[2] = cross(1, 2); insert(root, 2); prev[3] = 2; next[3] = 1; area[3] = cross(2, 3); insert(root, 3); ans = area[1] + area[2] + area[3]; tot = 3; } void findpred(int i, int j, int &l) { if (!i) return; if (d[te[i]].k - d[j].k > -eps) return findpred(link[i][0], j, l); else l = te[i], findpred(link[i][1], j, l); } int findlast(int i) { if (link[i][1] == 0) return te[i]; else return findlast(link[i][1]); } void cancel(int &i, int c) { if (!i) return; if (te[i] == c) { if (link[i][0] && link[i][1]) { int p = aux[link[i][1]] > aux[link[1][0]]; rotate(i, p); cancel(link[i][!p], c); } else i = link[i][link[i][1]!= 0]; } else { int p = d[c].k - d[te[i]].k > eps; cancel(link[i][p], c); } } void remove(int x) { next[prev[x]] = next[x]; prev[next[x]] = prev[x]; } int main() { int i, l, r; freopen("convex.in", "r", stdin); freopen("convex.out", "w", stdout); prepare(); scanf("%d", &n); for (i = 1; i <= n; i++) { d[++tot].read(); l = 0; d[tot].make(base); findpred(root, tot, l); if (l == 0) l = findlast(root); r = next[l]; if (cross2(l, tot, l, r) >= 0) { for (;cross2(tot, prev[l], tot, l) <= 0; ) cancel(root, l), ans -= area[l], remove(l),l = prev[l]; for (;cross2(tot, next[r], tot, r) >= 0; ) cancel(root, r), ans -= area[r], remove(r),r = next[r]; prev[tot] = l; next[tot] = r; next[l] = tot; prev[r] = tot; ans += (area[tot] = cross(l, tot)); long long g = area[r]; ans += ((area[r] = cross(tot, r)) - g); insert(root, tot); } printf("%I64d\n", abs(ans)/9); } return 0; }