掌握用 STL 中的 SET 动态维护 “各类型凸壳” / “凸包”
前言
如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。
一、例题引入
题意:
主人公小智一共会捕捉 nnn 只宝可梦,宝可梦有两个属性,攻击值 AAA,防御值 BBB。每当捕捉到一只新的宝可梦 TTT,小智有两种方法判断这只宝可梦是否是无用的。
- 存在一只宝可梦 XXX,使得 X.A>T.AX.A > T.AX.A>T.A 并且 X.B>T.BX.B > T.BX.B>T.B
- 存在两只宝可梦 X,YX,YX,Y,使得 c∗X.A+(1−c)∗Y.A>T.Ac*X.A+(1-c)*Y.A>T.Ac∗X.A+(1−c)∗Y.A>T.A 并且 c∗X.B+(1−c)∗Y.B>T.Bc*X.B+(1-c)*Y.B>T.Bc∗X.B+(1−c)∗Y.B>T.B,0≤c≤10\leq c\leq 10≤c≤1
每当捕捉到一只新宝可梦,需要输出当前共有几只无用宝可梦。(1≤n≤105,0≤Ai,Bi≤109)(1\leq n\leq 10^5,0\leq A_i,B_i\leq 10^9)(1≤n≤105,0≤Ai,Bi≤109)
题目来源:Gym 102302-I
思路:
一开始一直在推导式子,妄图想要用一个指标同时维护这两个变量,然后就自闭了…
后来在队友提醒之下,发现这是一个线段参数方程。线段两端点为 (a,b)、(c,d)(a,b)、(c,d)(a,b)、(c,d),则线段上的点可以如下表示。
X=k∗a+(1−k)∗cY=k∗b+(1−k)∗dk∈[0,1]X=k*a+(1-k)*c \\ Y=k*b+(1-k)*d \\ k\in[0,1] X=k∗a+(1−k)∗cY=k∗b+(1−k)∗dk∈[0,1]
可能不够直观,但我们可以通过斜率来证明这是线段的参数方程。
X−aY−b=(1−k)∗(c−a)(1−k)∗(d−b)=c−ad−b=线段斜率\displaystyle\frac{X-a}{Y-b}=\displaystyle\frac{(1-k)*(c-a)}{(1-k)*(d-b)}=\displaystyle\frac{c-a}{d-b}=线段斜率 Y−bX−a=(1−k)∗(d−b)(1−k)∗(c−a)=d−bc−a=线段斜率
发现这是一个线段参数方程之后,此题就转化成了一个动态维护凸壳的问题,凸壳如下所示。
观察这个凸壳,我们定义比较函数如下。
struct Node {int x,y;bool operator < (Node T) const {return x == T.x ? y > T.y : x < T.x; }
}
然后每次增加一个点的时候,向两边进行扩展删点即可。删点的标准为左右两端点连线是否能够覆盖自己,如果能则删,不能则保留。具体过程见下文代码,代码很短,简单易懂。
例题总结:
此题最重要的两个关键点。
- 识别线段的参数方程
- 根据题意构建凸壳模型,并用 SET 求解
代码:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a; i <= b; i++)
typedef long long ll;
using namespace std;struct Node{ll x,y;Node operator - (Node p) const {return {x-p.x,y-p.y};}ll operator ^ (Node p) const {return x*p.y-y*p.x;}bool operator < (Node p) const {return (x == p.x ? y > p.y : x < p.x);}
};struct Hull : public multiset<Node>{bool inside(iterator p){auto t2 = next(p);if(t2 == end()) return 0;if(p == begin()) return t2->x > p->x && t2->y > p->y;auto t1 = prev(p);if(((*t1-*p)^(*t2-*p)) < 0) return 1;else return 0;}void ins(Node p){auto t = insert(p);if(inside(t)) { erase(t); return; }while(t != begin() && inside(prev(t))) erase(prev(t));while(next(t) != end() && inside(next(t))) erase(next(t));}
};int main()
{int n; scanf("%d",&n);Hull hull;rep(i,1,n){ll x,y; scanf("%lld%lld",&x,&y);hull.ins({x,y});printf("%d\n",i-(int)hull.size());}return 0;
}
二、各类型凸壳总结
凸壳处理过程中,主要注意点在于左右两边的垂直,在接下来所举的例子中,应仔细观察对于垂直的处理。
先按 xxx 升序,再按 yyy 升序
每次插入新节点,只需要插入 set 并找到对应位置,然后依次判断两边的节点是否应该被删除。(代码部分同例题)
- 上凸壳(可包含左边的垂直线段
- 下凸壳(可包含右边的垂直线段
先按 xxx 升序,再按 yyy 降序
- 上凸壳(可包含右边的垂直线段
- 下凸壳(可包含左边的垂直线段
特殊凸壳
此类凸壳两边都有垂直线段,因此我们需要重新思考左边垂直线段的问题。我们以左边点是否固定来进行区分。
- 左边点固定
- 如果左边点固定,我们则可以按照先按 xxx 升序,如果 x=xminx=x_{min}x=xmin,yyy 升序,否则 yyy 降序
- 左边点不固定
- 如果左边点不固定,我们可以考虑使用两个 SET 来进行维护,其中一个用于维护左边界垂直线,实现起来细节较繁琐
三、凸包维护
相较于种类繁多的凸壳,凸包维护较为清晰。
- 按照 “xxx 升序 +++ yyy 升序” 方法进行排序
- 起点为最小值处,终点为最大值处
- 上凸壳维护上半部分,下凸壳维护下半部分
- 用两个 setsetset 分别维护上下凸壳
- 上下凸壳判断一个点是否删除的代码不同,但均使用叉乘
- 判断点 PPP 是否该删去,左边点为 XXX,右边点为 YYY
- 上凸壳 (X−P)(X-P)(X−P)^(Y−P)<0(Y-P)<0(Y−P)<0 则删除点 PPP
- 下凸壳 (X−P)(X-P)(X−P)^(Y−P)>0(Y-P)>0(Y−P)>0 则删除点 PPP
后记
setsetset 维护 “凸壳” / “凸包” 的内容到此就结束了,最后补充几点:
- 除了 setsetset,也可以直接手写 SplaySplaySplay 等平衡树进行维护
- 凸包维护过程也可以寻找一个定点,根据极角序进行排序
最后祝大家 ACACAC 愉快,一起爱上凸包把!(๑•̀ㅂ•́)و✧
ACMACMACM 的旅行虽然充满荆棘但一抬头便能看见无数束光,请务必坚持下去,负重前行终有云开雾散之日!
掌握用 STL 中的 SET 动态维护 “各类型凸壳” / “凸包”相关推荐
- [爬虫架构] 如何在分布式爬虫架构中动态维护一个代理IP池(付费代理)
前言: 当分布式爬虫使用代理IP技术时,通过直接在爬虫程序中添加平台api接口的方式已经不能满足我们了,因为分布式的爬虫架构每秒的代理IP-URL的请求数会远远大于平台限制的请求频率,当然,对于没有限 ...
- STL中list用法详解
本文转载自百度文库.作者如下.其中下面的count, count_if等函数的使用有些陈旧,如在编译时遇到问题,请百度. 标准模板库(STL)介绍 作者:Scott Field 本文以List容器为例 ...
- 深入解析C++ STL中的常用容器
转载:http://blog.csdn.net/u013443618/article/details/49964299 这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中的 ...
- 一文搞懂 STL 中 deque 与 hashtab 的底层实现
文章目录 一.模板特化 二.设计容器必须定义的型别 三.deque 四.心心念念的优先队列 五.hashtable的构造 一.模板特化 针对任何模板参数更进一步的条件限制所设计出来的一个特化版本,如: ...
- STL中Vector的内存分配机制
一些好的公司校园招聘过程中(包括笔试.面试环节),经常会涉及到STL中vector的使用(主要是笔试)及其性能(面试)的分析.今天看了下相关文章,也写了几个小的测试程序跑了跑.算是总结下,希望对需要的 ...
- linux进程池动态维护,可直接商用的跨平台c,c++动态线程池,任务池stpool库
stpool是一个轻便高效的动态跨平台的线程池/任务池库. 常规线程池的缺点: 1. 总是启动时候就开启固定数目的线程,而不管系统的繁忙状态 (这是很浪费系统资源的). 2. 当任务繁重的时候,即使线 ...
- SAP QM中阶之动态修改规则创建
SAP QM中阶之动态修改规则创建 1, 执行事务代码QDR1或者如下的菜单路径, 可以用来创建动态修改规则. 点击菜单或者执行事务代码QDR1, 进入如下界面, 输入DMR的code,比如Z01,回 ...
- STL中基本容器有: string、vector、list、deque、set、map
为什么80%的码农都做不了架构师?>>> 在STL中基本容器有: string.vector.list.deque.set.map set 和map都是无序的保存元素,只能通过 ...
- C++ STL中vector用法简要总结
1.基本使用举例 下面的代码给出了vector的基本使用举例. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...
- 通过Flask和Redis构造一个动态维护的代理池
代理池的维护 目前有很多网站提供免费代理,而且种类齐全,比如各个地区.各个匿名级别的都有,不过质量实在不敢恭维,毕竟都是免费公开的,可能一个代理无数个人在用也说不定.所以我们需要做的是大量抓取这些免费 ...
最新文章
- Amber16和AmberTools16在CentOS 7下GPU加速版的安装
- 51nod1092(lcs简单运用/dp)
- matlab 凹盘,刹车盘凹槽是怎么形成的
- 【SAS BASE】SCAN函数
- 局域网内多台linux服务器时间同步的一种解决方案
- Media Query在SAP Spartacus里的用途
- 我的世界服务器显示不出地图,为什么我的世界服务器地图加载不了
- mysql 执行计划extra_mysql执行计划explain type和extra
- 虚方法(virsual method)
- 超级素数幂--全国模拟(一)
- [Spring实战系列](2)Maven创建Spring-HelloWorld项目
- 系列学习 Gateway 之第 1 篇 —— SpringCloud Gateway 简介,Gateway 入门实例
- 服务器文件夹加密码怎么设置,服务器文件夹设置密码
- windows10 右下角任务栏 隐藏图标
- java 异常提示_Java显示异常信息与异常分类
- 手机兼容性测试——机型选择(从系统、屏幕、型号考虑)
- 【Netty】九、Netty自定义协议
- 计算机触摸屏驱动版本在哪看,求解答笔记本触控板驱动在哪
- 1.5 mysql练习题37道,做完这些mysql练习题,立马让你进阶。(附答案)
- POJ - 1637 Sightseeing tour(混合图欧拉回路的求解--建图跑最大流)