代碼備份:動態維護半平面交/凸包

      以前寫的代碼,怕以後找不到了,放在這裏安全點。

       其實沒太多的技術含量,用平衡樹維護,配合鏈表,利用增量算法的思想,注意細節,使勁寫就行了。


   動態維護半平面交    

# 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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章