#19248. 亚马逊雨林的物种普查

亚马逊雨林的物种普查

你好,我是阿西莫夫。

在生态学(Ecology)的研究中,有两个非常容易混淆的概念:种群密度(Population Density)物种丰富度(Species Richness)

  • 前者关心的是“有多少只”(数量)。
  • 后者关心的是“有多少种”(种类)。

当你走进一片热带雨林,你可能会看到 100 只蚂蚁,但这只代表 1 个物种;而如果你看到了 1 只猴子、1 只鹦鹉和 1 条蛇,虽然数量只有 3,但物种丰富度却是 3。

std::set(集合) 是 C++ STL 中最能体现“物种丰富度”特性的容器。它的核心特征是:自动去重(重复插入无效)和自动排序(内部通常是红黑树)。

为了考察 set插入(去重)查找统计大小,我为你构思了这道题目。


[OI 题库] 亚马逊雨林的物种普查 (Biodiversity Survey)

题目背景

“大自然厌恶重复,但它热爱多样性。”

你是一名生物学家,正在亚马逊雨林进行生物多样性调查。你的任务是记录你所见到的每一个生物。

由于雨林环境复杂,你可能会多次遇到同一种生物(例如,你今天早上看到了一只蓝摩尔法蝶,下午又看到了一只)。但在计算物种丰富度时,重复看到的生物只能算作一种。

你需要编写一个智能记录系统,帮助你过滤重复数据,并实时回答关于物种存在性的问题。

题目描述

系统需要处理 NN 次操作,操作分为三种类型:

  1. 发现 (Observe)1 name 你在考察中发现了一个生物,其学名为 name(字符串)。请将其加入数据库。
    • 注意:如果该物种已经在数据库中,系统会自动忽略,不会重复计数。
  2. 查证 (Check)2 name 你需要确认名为 name 的物种是否已经被记录过。
    • 如果已记录,输出 Yes;否则输出 No
  3. 统计 (Report)3 输出当前的物种丰富度(即数据库中不同物种的总数量)。

输入格式

第一行一个整数 NN,表示操作次数。 接下来 NN 行,每行包含一个操作指令。

  • name 是由英文字母组成的字符串(区分大小写)。

输出格式

  • 对于操作 2,输出 YesNo
  • 对于操作 3,输出一个整数。
  • 每个输出占一行。

样例数据

样例 1

输入 (Input)

8
1 Morpho
1 Jaguar
1 Morpho
3
2 Jaguar
2 Capybara
1 Capybara
3

输出 (Output)

2
Yes
No
3

样例解析 (Explanation)

  1. 1 Morpho:发现蓝闪蝶。集合变为 {Morpho}
  2. 1 Jaguar:发现美洲豹。集合变为 {Jaguar, Morpho}
  3. 1 Morpho:又发现蓝闪蝶。已存在,自动去重。集合仍为 {Jaguar, Morpho}
  4. 3:统计丰富度。当前大小为 2
  5. 2 Jaguar:查证美洲豹。存在,输出 Yes
  6. 2 Capybara:查证水豚。不存在,输出 No
  7. 1 Capybara:发现水豚。集合变为 {Capybara, Jaguar, Morpho}
  8. 3:统计丰富度。当前大小为 3

数据范围

  • 1N100,0001 \le N \le 100,000
  • 字符串长度 20\le 20
  • 考察点set 的自动去重特性和 O(logN)O(\log N) 的快速查找能力。

阿西莫夫的解题指南

这道题是 STL std::set 的教科书级应用。

  1. 去重:不需要像数组那样遍历查找“是否存在”,直接调用 st.insert(val)。如果元素已存在,set 会什么都不做。
  2. 查找:使用 st.count(val) 或者 st.find(val)
    • count() 返回 1 表示存在,0 表示不存在(因为 set 里没有重复元素)。
    • 这比在 vector 中查找(O(N)O(N))要快得多(O(logN)O(\log N))。
  3. 统计st.size() 直接返回不同元素的个数。