以前写的代码,怕以后找不到了,放在这里安全点。
其实没太多的技术含量,用平衡树维护,配合链表,利用增量算法的思想,注意细节,使劲写就行了。
动态维护半平面交
# 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;
}