🗂️ C++ STL • Associative Container

CHUYÊN ĐỀ MULTIMAP
trong C++

Multimap dùng để lưu nhiều cặp key → value, trong đó một key có thể xuất hiện nhiều lần. Trang này tổng hợp lý thuyết, ví dụ, lỗi thường gặp và 5 bài tập kèm bộ test.

key trùngKhác map
tự sắp xếpTheo key
equal_rangeLấy nhóm cùng key
O(log n)Tìm, thêm, xóa
1

Khái niệm multimap

multimap là gì?

multimap<Key, Value> là container liên kết trong C++ STL, lưu các phần tử dạng pair<const Key, Value>. Khác với map, nhiều phần tử trong multimap có thể có cùng key.

Ghi nhớ: Nếu một từ có nhiều nghĩa, một điểm số có nhiều học sinh, một thời điểm có nhiều sự kiện, ta có thể dùng multimap.

Đặc điểm quan trọng

  • Các phần tử được sắp xếp theo key.
  • Key trùng nhau được phép tồn tại.
  • Duyệt container sẽ đi theo thứ tự không giảm của key.
  • Thao tác tìm kiếm, thêm, xóa thường có độ phức tạp logarit.
Lưu ý: Muốn truy cập tất cả value của một key, nên dùng equal_range(key).
2

Cú pháp khai báo

#include <bits/stdc++.h>
using namespace std;

multimap<string, int> diem;       // key: tên, value: điểm
multimap<int, string> hocSinh;    // key: điểm, value: tên
multimap<int, string, greater<int>> giam; // key giảm dần
Key
Dùng để sắp xếp và tìm kiếm.
Value
Dữ liệu đi kèm với key.
Compare
Mặc định tăng dần theo key, có thể dùng greater<>.
3

Các thao tác thường dùng

Thao tácCú phápÝ nghĩa
Thêm phần tửmp.insert({'}key, value{'})Thêm một cặp key-value, kể cả khi key đã tồn tại.
Đếm theo keymp.count(key)Trả về số phần tử có key đang xét.
Tìm một phần tửmp.find(key)Trả về iterator đến một phần tử có key đó, hoặc end().
Lấy cả nhómmp.equal_range(key)Trả về cặp iterator bao phủ tất cả phần tử có cùng key.
Cận dướimp.lower_bound(key)Iterator đầu tiên có key không nhỏ hơn key đang xét.
Cận trênmp.upper_bound(key)Iterator đầu tiên có key lớn hơn key đang xét.
Xóa theo keymp.erase(key)Xóa tất cả phần tử có key đó.

Ví dụ 1: in tất cả điểm của một học sinh

multimap<string, int> mp;
mp.insert({"An", 8});
mp.insert({"Binh", 7});
mp.insert({"An", 9});

auto range = mp.equal_range("An");
for (auto it = range.first; it != range.second; ++it) {
    cout << it->second << " ";
}
// Kết quả: 8 9

Ví dụ 2: liệt kê theo khoảng key

multimap<int, string> mp;
mp.insert({8, "An"});
mp.insert({9, "Binh"});
mp.insert({8, "Chi"});

int L = 8, R = 9;
for (auto it = mp.lower_bound(L); it != mp.upper_bound(R); ++it) {
    cout << it->second << " ";
}
// In các value có key trong [L, R]
4

So sánh map và multimap

Tiêu chímapmultimap
Key trùng nhauKhông cho phépCho phép
Truy cập bằng []Có thể dùng mp[key]Không dùng được [] như map
Thêm phần tử cùng keyGhi đè hoặc giữ một value tùy cách thêmThêm thêm một phần tử mới
Dùng khiMỗi key chỉ có một valueMỗi key có thể có nhiều value
5

Ứng dụng thường gặp

Từ điển nhiều nghĩa

Một từ khóa có thể có nhiều nghĩa khác nhau.

Điểm số

Một điểm số có thể có nhiều học sinh cùng đạt.

Lịch sự kiện

Một thời điểm có thể có nhiều sự kiện.

Log hệ thống

Một mã người dùng có nhiều lần truy cập hoặc nhiều giao dịch.

Nhóm dữ liệu

Gom nhiều value theo cùng một key để xử lý nhanh.

Truy vấn khoảng

Dùng lower_bound và upper_bound để lấy dữ liệu theo khoảng key.

6

5 bài tập bổ sung

BàiTên bàiKỹ năng chínhTest
1Từ điển nhiều nghĩainsert, equal_range20 test / 4 sub
2Liệt kê học sinh theo khoảng điểmlower_bound, upper_bound20 test / 4 sub
3Thêm, xóa, thống kê bản ghierase, count, equal_range20 test / 4 sub
4Lịch sự kiệntruy vấn khoảng động20 test / 4 sub
5Tra cứu sản phẩm theo giákey trùng + query20 test / 4 sub

Bài 1. Từ điển nhiều nghĩa

MMTUDIEN.*

Cho n cặp từ khóa - nghĩa. Một từ khóa có thể xuất hiện nhiều lần với nhiều nghĩa khác nhau. Với mỗi truy vấn, hãy in tất cả nghĩa của từ đó theo thứ tự xuất hiện trong dữ liệu vào.

Dữ liệu vàon q, n dòng word meaning, q dòng word.
Kết quảMỗi truy vấn in các nghĩa hoặc NONE.
Giới hạn1 ≤ n,q ≤ 105

Input

5 3
code ma_lenh
map anh_xa
code lap_trinh
key khoa
code chuong_trinh
code
map
stack

Output

ma_lenh lap_trinh chuong_trinh
anh_xa
NONE
Gợi ý: dùng multimap<string,string>equal_range.

Bài 2. Liệt kê học sinh theo khoảng điểm

MMDIEM.*

Cho danh sách học sinh và điểm. Có q truy vấn [L, R]. Với mỗi truy vấn, in tên các học sinh có điểm nằm trong đoạn [L, R], theo thứ tự điểm tăng dần.

Dữ liệu vàon q, n dòng name score, q dòng L R.
Kết quảTên học sinh hoặc NONE.
Giới hạn0 ≤ score ≤ 109

Input

5 2
An 8
Binh 7
Chi 8
Dung 10
Hoa 6
7 8
9 10

Output

Binh An Chi
Dung
Gợi ý: dùng multimap<int,string>, duyệt từ lower_bound(L) đến upper_bound(R).

Bài 3. Thêm, xóa, thống kê bản ghi

MMXOA.*

Ban đầu có n bản ghi dạng key value. Sau đó có q thao tác: 1 k v thêm bản ghi, 2 k xóa tất cả bản ghi có key k, 3 k in số lượng và tổng value của key k.

Dữ liệu vàon q, n dòng k v, q dòng thao tác.
Kết quảVới thao tác 3, in count sum.
Giới hạn1 ≤ q ≤ 105

Input

4 5
1 10
2 5
1 7
3 8
3 1
1 1 4
3 1
2 1
3 1

Output

2 17
3 21
0 0
Gợi ý: dùng erase(key) để xóa toàn bộ nhóm cùng key.

Bài 4. Lịch sự kiện

MMLICHSU.*

Có n sự kiện ban đầu, mỗi sự kiện có thời điểm t và tên. Có q thao tác: 1 L R in các sự kiện có thời điểm trong [L, R]; 2 t name thêm sự kiện mới.

Dữ liệu vàon q, n dòng t name, q dòng thao tác.
Kết quảVới thao tác 1, in tên sự kiện hoặc NONE.
Giới hạn0 ≤ t ≤ 109

Input

3 4
5 hoc
10 thi
10 nop
1 1 10
2 7 on
1 6 9
1 11 20

Output

hoc thi nop
on
NONE
Gợi ý: multimap cho phép nhiều sự kiện cùng thời điểm.

Bài 5. Tra cứu sản phẩm theo giá

MMSANPHAM.*

Quản lý danh sách sản phẩm theo giá. Có q thao tác: 1 p in các mã sản phẩm có giá p; 2 L R in số sản phẩm có giá trong [L, R]; 3 p code thêm sản phẩm mới.

Dữ liệu vàon q, n dòng price code, q thao tác.
Kết quảVới thao tác 1 hoặc 2, in kết quả tương ứng.
Giới hạn1 ≤ n,q ≤ 105

Input

4 5
10 A
20 B
10 C
30 D
1 10
2 10 20
3 10 E
1 10
2 25 40

Output

A C
3
A C E
1
Gợi ý: lấy nhóm giá đúng bằng equal_range(p), đếm khoảng bằng lower_boundupper_bound.
7

Nguồn tham khảo

  • cppreference: std::multimap, equal_range, lower_bound, upper_bound, erase.
  • cplusplus.com: multimap reference.
  • Tài liệu gốc do thầy/cô cung cấp: multimap trong C++.
style> body { user-select: none; }