洛谷 P5266:学籍管理与 map CRUD
这题的重点不是复杂算法,而是把
map当成一张“姓名 → 成绩”的字典,完成增改查删和人数统计。
1. map 是什么
map<string, int> mp;
表示:
key(姓名) → value(成绩)
Alice → 95
Bob → 87
数组通过数字下标访问:
a[3] = 95;
map 则通过键访问:
mp["Alice"] = 95;
本题的四种操作可以直接对应成:
| 操作 | 含义 | map 写法 |
|---|---|---|
1 name score |
新增或修改 | mp[name] = score |
2 name |
查询 | mp.find(name) |
3 name |
删除 | mp.erase(it) 或 mp.erase(name) |
4 |
统计人数 | mp.size() |
2. 新增与修改:operator[]
string name;
int score;
cin >> name >> score;
mp[name] = score;
这一句同时完成两件事:
name不存在:新增一条记录;name已存在:覆盖旧成绩。
例如:
mp["Alice"] = 80;
mp["Alice"] = 95;
最终只有一条记录:Alice → 95。
3. 查询:find 和 end
auto it = mp.find(name);
it 可以先理解成“指向某条键值对的迭代器”。如果没有找到,find 返回 mp.end():
if (it != mp.end())
{
cout << it->second << '\n';
}
else
{
cout << "Not found\n";
}
mp.end() 不是最后一个元素,而是“最后一个元素后面的位置”,所以不能解引用。判断逻辑就是:
find(name) == end() → 没找到
find(name) != end() → 找到了
4. it->first 和 it->second
map 中的一条记录可以理解成:
pair<string, int>
因此:
it->first // key:姓名
it->second // value:成绩
例如记录是:
Alice → 95
那么 it->first 是 Alice,it->second 是 95。
5. 删除:先找再删
auto it = mp.find(name);
if (it == mp.end())
{
cout << "Not found\n";
}
else
{
mp.erase(it);
cout << "Deleted successfully\n";
}
也可以直接写:
mp.erase(name);
但先 find 再 erase 更适合本题,因为题目要求区分“删除成功”和“没有这个人”。
6. 完整 C++ 代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int q;
cin >> q;
map<string, int> mp;
while (q--)
{
int op;
cin >> op;
if (op == 1)
{
string name;
int score;
cin >> name >> score;
mp[name] = score;
cout << "OK\n";
}
else if (op == 2)
{
string name;
cin >> name;
auto it = mp.find(name);
if (it == mp.end())
{
cout << "Not found\n";
}
else
{
cout << it->second << '\n';
}
}
else if (op == 3)
{
string name;
cin >> name;
auto it = mp.find(name);
if (it == mp.end())
{
cout << "Not found\n";
}
else
{
mp.erase(it);
cout << "Deleted successfully\n";
}
}
else if (op == 4)
{
cout << mp.size() << '\n';
}
}
return 0;
}
7. 执行流程示例
1 Alice 95 → 新增 Alice,输出 OK
2 Alice → 查到 95
1 Alice 100 → 修改 Alice,输出 OK
3 Alice → 删除成功
2 Alice → Not found
4 → 输出当前记录数
while (q--) 表示总共处理 q 条操作;每轮先读 op,再根据操作编号进入对应分支。
8. 两个容易写错的地方
注释写法
下面的写法是错误的:
*// 优化 *
正确写法是:
// 优化
/* 优化 */
读取失败判断
if (!(cin >> q)) return 0;
表示读取 q 失败就退出。它在通用程序里有意义,但竞赛题通常保证输入合法,先写:
cin >> q;
即可,先把题目逻辑读懂更重要。
9. 这道题真正要记住什么
map<string, int> mp; // 创建字典
mp[name] = score; // 新增 / 修改
mp.find(name); // 查找
mp.erase(name); // 删除
mp.size(); // 统计
it->first; // 键
it->second; // 值
可以把整题记成一张表:输入 1 是新增一行,输入 2 是查一行,输入 3 是删一行,输入 4 是统计当前行数。理解这个对应关系,比死记 map 的语法更重要。