bzoj2300: [HAOI2011]防线修建 计算几何 凸包

本文介绍了一种动态维护凸包的算法实现,该算法通过离线处理方式优化了点的添加过程,并使用 set 数据结构来存储凸包上的点。文章详细展示了如何在添加新的点时更新凸包,并提供了完整的 C++ 代码示例。

动态维护凸包。

由于只用管上凸部分,所以按x为第一关键字排序。

由于删点很麻烦,我们可以考虑离线加点。

这样就得把在凸包上的点建一个set

每次加点,如果点在凸包内那么直接返回。

如果在凸包外,就应该找到坐支和右支这样才能形成一个新的凸包。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
using namespace std;
#define pi acos(-1.0)
#define maxn 410000
#define eps 1e-10
double now,ans[200005];
int T,t1,t2,n,m,Q,b[200005];
bool mark[100005];
struct node
{
    double x,y;
}p[maxn],del[maxn];
set<node>myset;
double sqr(double x)
{
    return x*x;
}
double dis(node a,node b)
{
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
double operator * (node a,node b)
{
    return a.x*b.y-a.y*b.x;
}
node operator - (node a,node b)
{
    node t;
    t.x=a.x-b.x; t.y=a.y-b.y;
    return t;
}
node operator + (node a,node b)
{
    node t;
    t.x=a.x+b.x; t.y=a.y+b.y;
    return t;
}
bool cmp(node a,node b)
{
    if(fabs((a-p[1])*(b-p[1]))<eps)return dis(p[1],a)<dis(p[1],b);
    return (a-p[1])*(b-p[1])>0;
}
bool operator<(node a,node b)
{
	if(fabs(a.x-b.x)<eps) return a.y<b.y;
	return a.x<b.x;
}
void insert(int a,int b)
{
	node x=(node){a,b};
	set<node>::iterator r=myset.lower_bound(x),l=r,t;
	l--;
	if((*r-*l)*(x-*l)<0) return;
	now-=dis(*l,*r);
	myset.insert(x);
	while(l!=myset.begin())
    {
        t=l;l--;
        if( (*t-x)*(*l-x)>0 ) break;
        now-=dis(*t,*l);
		myset.erase(t);
    }
    while(1)
	{
		t=r;r++;
		if(r==myset.end())break;
		if((*r-x)*(*t-x)>0)break;
		now-=dis(*t,*r);
		myset.erase(t);
	}
	myset.insert(x);
	l=r=t=myset.find(x);
	l--;r++;
	now+=dis(*l,x)+dis(*r,x);
}
int main()
{
    scanf("%d",&n);
    myset.insert((node){0,0});
    myset.insert((node){n,0});
    node cap;
    scanf("%lf%lf",&cap.x,&cap.y);
    myset.insert(cap);
    now+=dis((node){0,0},cap);
	now+=dis((node){n,0},cap);
	scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
	int typ,x;
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++)
	{
		scanf("%d",&typ);
		if(typ==1)
        {
            scanf("%d",&x);
            del[++t1]=p[x];
            mark[x]=1;
        }
		else b[++t2]=t1;
	}
	for(int i=1;i<=m;i++) if(!mark[i])insert(p[i].x,p[i].y);
	int T=t1;
	for(int i=t2;i;i--)
	{
		while(T>b[i])
		{
			insert(del[T].x,del[T].y);
			T--;
		}
		ans[i]=now;
	}
	for(int i=1;i<=t2;i++)printf("%.2lf\n",ans[i]);
    return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值