算法

竞赛编程必备数据结构

更新于 2026-03-15

一份会超时的解法和一份能拿满分的解法之间的差别,很少仅仅在于巧思——通常是在恰当的时机选对了恰当的数据结构。

在竞赛编程中,你会拿到一道题、一个时间限制(通常是一到两秒)以及紧张的内存预算。同样的逻辑,会因为你的操作是在线性时间、对数时间还是常数时间内完成而决定通过与否。因此,熟练掌握一组聚焦的竞赛编程数据结构,是学生能做的回报最高的事情之一。下面我们将逐一讲解最重要的几种结构,大致按你应当学习的顺序排列,并把它们对应到各自能解锁的题型。

从基础打起

在伸手去拿任何花哨的工具之前,先把基本组件用熟。大多数赛题——以及绝大多数入门级题目——仅凭这些就能解决:

  • 数组与动态数组(vector),用于按下标存储和前缀和。
  • 栈与队列,用于排序、回溯和广度优先遍历。
  • 哈希表与哈希集合,用于近似常数时间的查找、计数和去重。
  • 有序集合与有序映射(平衡二叉搜索树),当你既需要查找需要有序时使用。
  • 优先队列(堆),用于始终取出下一个最小或最大的元素——它是 Dijkstra 算法和贪心调度的骨干。

在 C++ 中,所有这些都随标准模板库(STL)一同提供,这也是 C++ 在竞赛中始终流行的原因之一。把 STL 用熟,意味着你能把比赛时间花在思考问题本身,而不是重新实现一个堆。如果你才刚刚起步,我们的竞赛编程项目会通过有意识、有评分的练习培养这种熟练度,而不是零散地刷题。

能夺奖的那些结构

当基础变成本能之后,一小批更进阶的结构会在更难的组别中反复出现。其中三种值得单独点名:

并查集(Union-Find)

并查集(DSU)维护一组被划分为若干不相交集合的元素,提供两种操作:find(这个元素属于哪个集合?)和 union(合并两个集合)。配合路径压缩和按秩合并,两种操作都能在近乎常数的摊还时间内完成。它是连通性问题以及 Kruskal 最小生成树算法的标准工具。

树状数组(Fenwick Tree)

树状数组由 Peter Fenwick 于 1994 年首次提出,能在 O(log n) 时间内回答前缀和查询并完成单点更新。它占用与原数组相同的内存,且代码简短,因此当一道题纯粹是单点更新加区间求和时,它就是首选。

线段树(Segment Tree)

线段树是更通用的表亲。每个节点代表数组的一个区间,让你能够回答区间最小值、最大值、求和或 gcd 查询——并且借助懒惰传播,可以一次性更新整个区间。它占用的内存大约是树状数组的四倍,代码也更长,所以实用的判断法则很简单:

当你只需要单点更新下的区间求和时,伸手去拿树状数组。一旦你需要最小值、最大值、区间更新,或任何树状数组无法求逆的操作,就立刻换成线段树。

这如何对应到真实赛事

美国计算机奥林匹克竞赛(USACO)把这种进阶过程展现得淋漓尽致。它在一年中举办数场线上比赛,每场三道题、满分 1000 分,学生依次晋升四个组别:Bronze、Silver、Gold 和 Platinum。

  • Bronze 奖励完全搜索、排序、贪心和基础数据结构。
  • Silver 倚重图与树,外加栈和队列。
  • Gold 引入滑动窗口以及单点更新区间求和问题——正是树状数组和线段树发挥价值的地方。
  • Platinum 要求精通区间查询、掌握进阶的树技巧,并能创造性地组合上述各种结构。
赛制、组别分数线和参赛资格可能逐赛季变化。在报名前,请务必到官方赛事网站确认当前规则,而不要依赖你在网上看到的某个固定数字。

这道阶梯令人鼓舞:你不必在第一天就掌握每一种结构。每个组别只要求一两件新工具,所以稳扎稳打的学习者可以一路攀登而不至于精疲力竭。在我们的赛事总览上浏览往年题目,是了解每个难度等级期待哪种结构的好方法。

一份实用的学习顺序

  1. 把数组、前缀和以及 STL 容器用熟。
  2. 加上栈、队列、堆和哈希表,直到它们成为本能。
  3. 学习并查集,然后是树状数组,再然后是线段树。
  4. 在经典题集上练习,并复盘每一道你没能做完的题。

持续且经过复盘的练习,每一次都胜过单纯堆量。如果你想要一条从 STL 基础到夺奖级区间查询的结构化路径——并得到经验丰富的教练的反馈——欢迎了解 BIAA 的竞赛编程方向,开始打造那套能把难题变成已解之题的工具箱。

预约免费测评

立即预约 →