计算几何
板题大赏。
板题1 凸包
我们先选最左下的一个点,它一定在凸包上。
于是将其他的点按照与左下点的极角排序,用单调队列维护外凸即可。(因为凸包的外边按照顺序一定是极角依次增大)
(p.s 对于此题,在一条线上的点不会影响最后答案,可以不用在极角的基础上按照长度排序)
1 |
|
板题2 旋转卡壳
求最远点对。
显而易见最远点对一定在凸包上。于是考虑在凸包上如何求解。
我们随便选一条边,枚举得出这条边的最远点(可以用叉积面积快速判断),按照逆时针枚举边,注意到最优点的位置也是顺时针变化,于是枚举完一遍边的同时,最优点对也只会旋转一圈。
(p.s 注意这里所有点可能在一条直线上,所以排序时按照极角+长度排序,去凸包时自动只保留最远两点)
code
1 |
|
板题3 半平面交
基本流程如下:
-
把所有边按照极角排序
-
排序时如果极角相同,我们保留最右的边(默认有效半平面为左边)
-
排序后按照极角从小到大枚举边,与当前单调队列的队首队尾点和次队首队尾点合并,如果可以完全替代则替代掉。(单调队列基本操作)
-
结束后不要忘记对最后的单调队列首尾各来一次判断(因为你单调队列只保证了一段最优)
-
我们得到了构成最后面积交的线段(且是按极角排序后的),于是一一算出交点即可。
-
最后根据交点套面积公式即可
一点补充:
-
如果三条边中,两条边交点在第三边合法侧,那么第三边会被覆盖,可以删去。
-
因为极角本身是圆,故每次按极角大小加入一条新边时,对队首队尾都可能有威胁,于是从两个方向删边即可。
-
注意加完边后,我们只保证了从第一条边到最后一条边连续的边不会被删掉,但是这只是线形的(有可能新加的边本身就是废边,但是这条废边也许会因为后来加的都是废边而不被删掉),于是再把头和尾做一次删边。
-
如果实现时把上一个交点在线上也t–(保证精度),那么就要保证最后从头从尾删数时保证(保证判断的三条线段不会有相等)/*循环里还是
-
数据过大要用,否则就会像我这样调一下午。
-
最后记得特判掉总点数小于3的情况,否则会输出non且不会报错。(其实死咬住求交点时除数不为0即可(即直线不平行))
-
保证如果有解一定是封闭图形(如果图形不封闭,我们就要人为加上边界线)
1 |
|
板题口糊完了,看几道简单的例题
例题1 [SCOI2007]最大土地面积
四边形在凸包上
对于一个四边形,我们枚举对角线,假设我们已经确定了一条对角线,那么现在的目的即是找到对角线两侧最大三角形面积,由于是凸包,显然两侧的点到对角线距离是单峰,于是貌似三分可以做大貌似可以过了。
继续考虑优化,我们枚举a,再枚举b,假设a-b就是对角线,于是在枚举b的时候,两侧的最远点也是按顺序转动,于是单调队列维护即可。
code
1 | //我也不知道为什么之前写计算几何代码这么丑 |
例题2 [CQOI2005]三角形面积并
扫描线求解面积并。
我们算出每一个交点,那么扫描线停留在这些交点的x坐标上,而相邻两条扫描线的贡献是,扫描线的距离乘上扫描线的中位线截所有三角形的长度的并。
暴力搞出来就好了。
时间复杂度
code
1 |
|
例题 3 Last Stardust
n个点,一条固定线段AB,求多少点对满足一个点在另一个点与AB形成的三角形内,数据保证不会有三点共线。
对于两个点,只要满足与AB两点的极角,一大一小即满足题意。转化为二位偏序问题。
按照与AB的极角排序后,树状数组依次枚举统计答案即可。
(注意AB两侧的点分开计算)
(另外关于按照AB极角排序,可以按照与叉积排序后搞定顺序,或者用余弦定理搞定cos,再lowbound搞定顺序,精度上优选叉积排序,但是余弦定理相对好写)
code
1 |
|
例题4 [JSOI2016]炸弹攻击2
注意到所有敌人都在塔和能量源的上方,所以一个合法光线等价于一个三元组满足且与夹角小于。
于是我们按照级角排序,维护每一个线段作为左端点的最右端点(双指针维护),然后提前维护一些前缀和,可以做到对每个左端点计算答案即可。
关于实现:在级角排序时,最方便用,如果要叉积比较必须要选一组基准边,保证一定可以构成排序,不要像我一样sb到直接比较两边叉积。
code
1 |
|
例题5 [SCOI2015]小凸想跑步
对每条边与AB等分面积中位线可以用叉积暴算后化简,发现是一条直线(这个从几何角度分析也可以发现)
于是就是个裸的半平面交了
(时刻关心除数为0的情况,ta真的很致命qwq
code
1 |
|
例题6 [HNOI2012]射箭
不难发现对一个标靶合法射击二次函数的取值满足一次函数关系,故二分后半平面交即可,只要半平面有解即是可行。
(对于这种可能不是围成封闭图形的半平面交,预处理要加上四条边界线)
1 |
|