8.19

vector 与堆(大根堆小根堆)的巧妙转化

trigger:动态求第k大,(其实中位数就是求动态第(1+n)/2大)

P1168 中位数

开vector加数,若当前为第奇数个,输出v[(i-1)/2],注意vector从0开始存;

P1801 黑匣子_NOI导刊2010提高(06)

对顶堆做法:代码

Luogu P2949 [USACO09OPEN]工作调度Work Scheduling

首先只要有贪心基础就不难想出一个解题思路:因为所有工作的花费时间都一样,我们只要尽量的选获得利润高的工作,以及对于每个所选的工作,我们尽量让它在更靠近它的结束时间的地方再来工作

但是两种条件我们并不好维护,这种两个限制条件的题目也是有一种挺经典的做法的:对一个限制条件进行排序,对于另一个限制条件使用某些数据结构来维护(如treap,线段树,树状数组之类),但是这并不在我们今天的讨论范畴QAQ

考虑怎么将这两个条件“有机统一”。

排序的思路是没有问题的,我们可以对每个工作按照它的结束时间进行排序,从而来维护我们的第二个贪心的想法。

那么对于这样做所带来的一个冲突:对于一个截止时间在d的工作,我们有可能把0~d秒全都安排满了(可能会有多个任务的截止时间相同)

怎么解决这种冲突并保证答案的最有性呢?

一个直观的想法就是把我们目前已选的工作全部都比较一下,然后选出一个创造的利润最低的工作(假设当前正在决策的这个工作价值很高),然后舍弃掉利润最低的工作,把这个工作放进去原来的那个位置。(因为我们已经按照结束时间排序了,所以舍弃的那个任务的截止完成时间一定在当前决策的工作的之前)

但是对于大小高达10^6的n,O(n^2)的复杂度显然是无法接受的,结合上面的内容,读者们应该也不难想出,可以使用堆来优化这个操作

我们可以在选用了这个工作之后,将当前工作放入小根堆中,如果堆内元素大于等于当前工作的截止时间了(因为这道题中,一个工作的执行时间是一个单位时间),我们就可以把当前工作跟堆顶工作的价值比较,如果当前工作的价值较大,就可以将堆顶弹出,然后将新的工作放入堆中,给答案加上当前工作减去堆顶元素的价值(因为堆顶元素在放入堆中的时候价值已经累加进入答案了)。如果堆内元素小于截止时间那么直接放入堆中就好

至此,我们已经可以以O(nlogn)

的效率通过本题

而通过这道题我们也可以发现,只有在优化我们思考出来的贪心操作的时间复杂度时,我们才用到了堆。正如我们先前所说到的,在大部分有一定难度的题目里,堆都是以一个“工具”的身份出现,用于优化算法(大多时候是贪心)的时间复杂度等

猜你喜欢

转载自www.cnblogs.com/sjsjsj-minus-Si/p/11635387.html
今日推荐