【计算几何】使用set维护凸壳。

1.动态凸包是一类经典的题目,题目的大概意思就是:在添加和删除平面上的一些点,然后询问这些点构成的凸包的信息。典型题目:HAOI 2011 构建。有多种写法,可以用Splay维护,也可以用set维护。我们来讨论一下如何使用set维护动态凸包,但是有一个缺陷,就是只支持添加点,删除点的是不行的,但是我们可以把操作离线下来,倒着扫,删点就成了加点。

(1)首先我们把所有的点按照x排序,x相同的按照y排序。假设我们已经得到了某个凸包:

                                                         

现在加入x点,

                                  

显然,x点是要凸包上的一个点,我们首先在set内lowerbound一个点,r,然后r像后边退一个得到l。因为我们是看出来这个点的确实需要被加入凸包集合内,但是如何判断呢?

                                  

做rx向量,lx向量,我们可以看出来,lx*rx(叉乘)是一个正的数字,直白点就是说rx转向rx的角度是一个小于180的角,那么这个点就要被加入凸包内,否则不加入。加入以后,我们如何构建新的凸包呢?方法类似,因为我们已经得到了l,r.以l为例:

                              

将l向左推移,得到l1,发现l1x转向lx的夹角的sin值也是一个正值,所以l1继续留在凸包内部,否则从集合删除这个点。这样把l一直左推到起点就完成了左半部分凸包的更新,右半部分类似。这样每次更新的复杂度是O(size(set))的。所以这种方法虽然比Splay好实现,但是极限数据时可能会不是很好。

简单的贴一下代码:

/*
凸包被存在st中,st是一个set。point结构体重载了*,重载为叉积。it为宏定义,为set的迭代器
ans:凸包的周长,calc()为计算两点间距离的函数。动态维护凸包的周长
*/
inline void insert(point x) 
{
	it r = st.lower_bound(x), l = r, t;
	l--;
	if ((*r - *l) * (x - *l) < 0)return;
	ans -= (*r - *l).calc();
	while (1)
	{
		t = r, r++;
		if (r == st.end())break;
		if ((*r - x) * (*t - x) > 0)break;
		ans -= (*r - *t).calc();
		st.erase(t);
	}
	while (l != st.begin()) 
	{
		t = l, l--;
		if ((*l - x) * (*t - x) < 0)break;
		ans -= (*l - *t).calc();
		st.erase(t);
	}
	st.insert(x);
	l = r = st.find(x);
	l--, r++;
	ans += (*r - x).calc(), ans += (*l - x).calc();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值