洛谷 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 的语法更重要。