前言

如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。

一、例题引入

题意:

主人公小智一共会捕捉 nnn 只宝可梦,宝可梦有两个属性,攻击值 AAA,防御值 BBB。每当捕捉到一只新的宝可梦 TTT,小智有两种方法判断这只宝可梦是否是无用的。

  1. 存在一只宝可梦 XXX,使得 X.A>T.AX.A > T.AX.A>T.A 并且 X.B>T.BX.B > T.BX.B>T.B
  2. 存在两只宝可梦 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;     }
}

然后每次增加一个点的时候,向两边进行扩展删点即可。删点的标准为左右两端点连线是否能够覆盖自己,如果能则删,不能则保留。具体过程见下文代码,代码很短,简单易懂。


例题总结:

此题最重要的两个关键点。

  1. 识别线段的参数方程
  2. 根据题意构建凸壳模型,并用 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 并找到对应位置,然后依次判断两边的节点是否应该被删除。(代码部分同例题)

  1. 上凸壳(可包含左边的垂直线段

  1. 下凸壳(可包含右边的垂直线段

先按 xxx 升序,再按 yyy 降序

  1. 上凸壳(可包含右边的垂直线段

  1. 下凸壳(可包含左边的垂直线段

特殊凸壳

此类凸壳两边都有垂直线段,因此我们需要重新思考左边垂直线段的问题。我们以左边点是否固定来进行区分。

  • 左边点固定

    • 如果左边点固定,我们则可以按照先按 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 维护 “凸壳” / “凸包” 的内容到此就结束了,最后补充几点:

  1. 除了 setsetset,也可以直接手写 SplaySplaySplay 等平衡树进行维护
  2. 凸包维护过程也可以寻找一个定点,根据极角序进行排序

最后祝大家 ACACAC 愉快,一起爱上凸包把!(๑•̀ㅂ•́)و✧

ACMACMACM 的旅行虽然充满荆棘但一抬头便能看见无数束光,请务必坚持下去,负重前行终有云开雾散之日!

掌握用 STL 中的 SET 动态维护 “各类型凸壳” / “凸包”相关推荐

  1. [爬虫架构] 如何在分布式爬虫架构中动态维护一个代理IP池(付费代理)

    前言: 当分布式爬虫使用代理IP技术时,通过直接在爬虫程序中添加平台api接口的方式已经不能满足我们了,因为分布式的爬虫架构每秒的代理IP-URL的请求数会远远大于平台限制的请求频率,当然,对于没有限 ...

  2. STL中list用法详解

    本文转载自百度文库.作者如下.其中下面的count, count_if等函数的使用有些陈旧,如在编译时遇到问题,请百度. 标准模板库(STL)介绍 作者:Scott Field 本文以List容器为例 ...

  3. 深入解析C++ STL中的常用容器

    转载:http://blog.csdn.net/u013443618/article/details/49964299 这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中的 ...

  4. 一文搞懂 STL 中 deque 与 hashtab 的底层实现

    文章目录 一.模板特化 二.设计容器必须定义的型别 三.deque 四.心心念念的优先队列 五.hashtable的构造 一.模板特化 针对任何模板参数更进一步的条件限制所设计出来的一个特化版本,如: ...

  5. STL中Vector的内存分配机制

    一些好的公司校园招聘过程中(包括笔试.面试环节),经常会涉及到STL中vector的使用(主要是笔试)及其性能(面试)的分析.今天看了下相关文章,也写了几个小的测试程序跑了跑.算是总结下,希望对需要的 ...

  6. linux进程池动态维护,可直接商用的跨平台c,c++动态线程池,任务池stpool库

    stpool是一个轻便高效的动态跨平台的线程池/任务池库. 常规线程池的缺点: 1. 总是启动时候就开启固定数目的线程,而不管系统的繁忙状态 (这是很浪费系统资源的). 2. 当任务繁重的时候,即使线 ...

  7. SAP QM中阶之动态修改规则创建

    SAP QM中阶之动态修改规则创建 1, 执行事务代码QDR1或者如下的菜单路径, 可以用来创建动态修改规则. 点击菜单或者执行事务代码QDR1, 进入如下界面, 输入DMR的code,比如Z01,回 ...

  8. STL中基本容器有: string、vector、list、deque、set、map

    为什么80%的码农都做不了架构师?>>>    在STL中基本容器有: string.vector.list.deque.set.map set 和map都是无序的保存元素,只能通过 ...

  9. 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 ...

  10. 通过Flask和Redis构造一个动态维护的代理池

    代理池的维护 目前有很多网站提供免费代理,而且种类齐全,比如各个地区.各个匿名级别的都有,不过质量实在不敢恭维,毕竟都是免费公开的,可能一个代理无数个人在用也说不定.所以我们需要做的是大量抓取这些免费 ...

最新文章

  1. Amber16和AmberTools16在CentOS 7下GPU加速版的安装
  2. 51nod1092(lcs简单运用/dp)
  3. matlab 凹盘,刹车盘凹槽是怎么形成的
  4. 【SAS BASE】SCAN函数
  5. 局域网内多台linux服务器时间同步的一种解决方案
  6. Media Query在SAP Spartacus里的用途
  7. 我的世界服务器显示不出地图,为什么我的世界服务器地图加载不了
  8. mysql 执行计划extra_mysql执行计划explain type和extra
  9. 虚方法(virsual method)
  10. 超级素数幂--全国模拟(一)
  11. [Spring实战系列](2)Maven创建Spring-HelloWorld项目
  12. 系列学习 Gateway 之第 1 篇 —— SpringCloud Gateway 简介,Gateway 入门实例
  13. 服务器文件夹加密码怎么设置,服务器文件夹设置密码
  14. windows10 右下角任务栏 隐藏图标
  15. java 异常提示_Java显示异常信息与异常分类
  16. 手机兼容性测试——机型选择(从系统、屏幕、型号考虑)
  17. 【Netty】九、Netty自定义协议
  18. 计算机触摸屏驱动版本在哪看,求解答笔记本触控板驱动在哪
  19. 1.5 mysql练习题37道,做完这些mysql练习题,立马让你进阶。(附答案)
  20. POJ - 1637 Sightseeing tour(混合图欧拉回路的求解--建图跑最大流)

热门文章

  1. apache log分析
  2. 使用基于轮询的SQL数据缓存依赖
  3. 置为底层_C语言之C语言的底层操作
  4. Hibernate 泛型实现 dao 层的基类
  5. scanf()接受不同类型的参数的一个例子
  6. 算法学习:最小生成树
  7. 1.自编码器(keras+mnist)
  8. c语言乘法怎么手写,发现要实现手写乘法计算过程也让我头疼
  9. nyoj 114某种排序(水 大数+优化大数)
  10. VF 动态规划系列dp入门