堆(Heap)是一种特殊的完全二叉树结构,通常分为最大堆和最小堆两种类型。
在最大堆中,父节点的值总是大于或等于其子节点的值;
而在最小堆中,父节点的值总是小于或等于其子节点的值。
堆常用于实现优先队列,在许多算法中也有重要应用,比如堆排序、Dijkstra算法等。
插入:向堆中添加一个新元素,并调整堆以保持其性质。
删除:移除堆顶元素(最大或最小元素),并重新调整堆。
获取最大/最小元素:直接访问堆顶元素即可获得。
Python 的 heapq
模块提供了对堆的支持,它实现了最小堆。以下是一个简单的例子:
import heapq
# 创建一个空堆
heap = []
# 向堆中插入元素
heapq.heappush(heap, 10)
heapq.heappush(heap, 20)
heapq.heappush(heap, 5)
print(heap)
# 获取堆顶元素(最小元素)
min_element = heap[0]
print("堆顶元素:", min_element)
# 移除堆顶元素
heapq.heappop(heap)
print("移除堆顶元素后的堆:", heap)
# 如果需要使用最大堆,可以通过插入负值来模拟
max_heap = []
heapq.heappush(max_heap, -10)
heapq.heappush(max_heap, -20)
heapq.heappush(max_heap, -5)
print(heap)
max_element = -max_heap[0] # 记得取负数得到原始的最大值
print("最大堆顶元素:", max_element)
注意:为了实现最大堆,我们需要存储元素的负值
因为 Python 标准库中的heapq
模块只提供最小堆的功能。
给定一个数列,初始为空,请支持下面三种操作:
第一行是一个整数,表示操作的次数 n n n。
接下来 n n n 行,每行表示一次操作。每行首先有一个整数 o p op op 表示操作类型。
对于每个操作 2 2 2,输出一行一个整数表示答案。
5
1 2
1 5
2
3
2
2
5
【数据规模与约定】
import heapq
hp = []
n = int(input())
for _ in range(n):
a = list(map(int, input().split()))
op = a[0]
if op == 1:
heapq.heappush(hp, a[1])
elif op == 2:
print(hp[0])
else:
heapq.heappop(hp)
牛客周赛 Round 82 E题 和+和
预处理前缀和后缀数组:
使用大根堆维护最小元素:
遍历所有可能的分割点:
import heapq
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
pre_a = [float('inf')] * (n + 1)
heap = [] # 最大堆(通过存储负数模拟)
sum_a = 0
for i in range(1, n + 1):
heapq.heappush(heap, -a[i - 1]) # 将当前元素加入堆中(存入负数表示最大堆)
sum_a += a[i - 1]
# 如果堆的大小超过 m,则移除堆顶元素(即最大的那个)
if len(heap) > m:
removed = -heapq.heappop(heap)
sum_a -= removed
# 如果堆中有正好 m 个元素,则记录当前的前缀和
if len(heap) == m:
pre_a[i] = sum_a
# 初始化后缀和数组 suf_b
suf_b = [float('inf')] * (n + 2)
heap = [] # 清空堆
sum_b = 0
# 计算后缀和
for i in range(n, 0, -1):
heapq.heappush(heap, -b[i - 1]) # 将当前元素加入堆中(存入负数表示最大堆)
sum_b += b[i - 1]
# 如果堆的大小超过 m,则移除堆顶元素(即最大的那个)
if len(heap) > m:
removed = -heapq.heappop(heap)
sum_b -= removed
# 如果堆中有正好 m 个元素,则记录当前的后缀和
if len(heap) == m:
suf_b[i] = sum_b
ans = float('inf')
for k in range(m, n-m + 1):
ans = min(ans, pre_a[k] + suf_b[k+1])
print(ans)
预处理前缀数组pre_a:
预处理后缀数组suf_b:
遍历分割点k:
这种方法利用堆高效地维护了最小的m个元素之和,预处理时间复杂度为O(n log m),遍历分割点的复杂度为O(n),整体复杂度为O(n log m),适用于大规模数据。
END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢