#19247. 湿地保护区的物种名录

湿地保护区的物种名录

你好,我是阿西莫夫。

在生物学野外考察(Field Survey)中,数据的采集往往具有高度的不确定性

比如,你在一个样方(Quadrat)里可能只发现 3 株植物,但在另一个样方里可能发现了 50 株。如果使用传统的固定长度数组(如 int arr[100]),开太小不够存,开太大浪费内存。

这正是 STL std::vector(动态数组) 大显身手的地方。它像一个可以自动伸缩的容器,完美适配这种“不知道会有多少个样本”的场景。

为了考察 vector插入(push_back)删除末尾(pop_back)大小查询(size)以及遍历(Iteration),我为你构思了这道题目。


[OI 题库] 湿地保护区的物种名录 (Species List of the Wetland)

题目背景

“生物多样性是生态系统健康的晴雨表。记录每一个生命,就是保护我们的未来。”

你是一名在湿地保护区工作的生态学家。保护区被划分成了 NN 个独立的观测区(Zone)。每天,考察队员们会前往各个区域进行物种调查。

由于每个区域的生物丰富度不同,你无法预知某个区域会发现多少种生物。你需要一个灵活的电子名录系统来记录这些数据。

系统需要支持以下操作:

  1. 记录(Record):在第 idid 号观测区发现了一个新物种(用编号表示),将其追加到该区域的记录列表中。
  2. 修正(Correct):队员报告第 idid 号观测区刚刚记录的最后一条数据有误(可能是看错了),需要将其删除。
  3. 归档(Archive):打印第 idid 号观测区目前记录的所有物种编号。

题目描述

保护区共有 NN 个观测区,编号从 11NN。初始时,所有区域的记录列表为空。 接下来有 MM 次操作,格式如下:

  • 1 id x:在第 idid 号区域的末尾添加物种编号 xx
  • 2 id:删除第 idid 号区域末尾的一个物种。
    • 注意:如果该区域列表为空,则忽略此操作。
  • 3 id:输出第 idid 号区域记录的所有物种编号。
    • 按记录顺序输出,中间用空格分隔。
    • 如果该区域为空,输出 Empty

输入格式

第一行两个整数 N,MN, M,分别表示观测区数量和操作次数。 接下来 MM 行,每行包含一个操作指令。

输出格式

对于每个操作 3,输出一行结果。

样例数据

样例 1

3 7
1 1 101
1 1 105
1 2 201
3 1
2 1
1 1 108
3 1
101 105
101 108

解析

  1. 区域1添加 101。Vec[1]: [101]
  2. 区域1添加 105。Vec[1]: [101, 105]
  3. 区域2添加 201。Vec[2]: [201]
  4. 输出区域1101 105
  5. 区域1删除末尾。Vec[1]: [101] (105被删了)
  6. 区域1添加 108。Vec[1]: [101, 108]
  7. 输出区域1101 108

样例 2 (边界测试)

2 5
2 1
3 1
1 1 50
2 1
3 1
Empty
Empty

解析

  1. 删除区域1末尾(原本就是空),忽略。
  2. 输出区域1:Empty
  3. 添加 50。
  4. 删除 50。
  5. 输出区域1:Empty

数据范围

  • 1N,M100,0001 \le N, M \le 100,000
  • 物种编号 xx 为整数,1x1091 \le x \le 10^9

阿西莫夫的解题指南

这道题是 vector 及其二维应用 的典型练习。

  1. 数据结构:因为有 NN 个区域,每个区域都需要一个动态数组,所以我们需要一个 vector 的数组vector<int> zones[100005];  这相当于一个二维结构,但每一行的长度是动态变化的。
  2. 核心操作
    • 添加:zones[id].push_back(x)
    • 删除:zones[id].pop_back()必须先检查 !empty()
    • 遍历:使用下标访问 zones[id][i] 或迭代器 for(int x : zones[id])
    • 判空:zones[id].empty()