Lesson 12 of 12

Make the state tell the truth

Maintain active frequencies, reset test cases, and debug the representation first.

Optional extension: keep only positive counts

When a frequency map represents an active bag, store a key exactly while its count is positive. Then size() equals the number of currently distinct values. Adding uses ++freq[x]; removing uses find so an absent removal does not create a record.

After decrementing a present count, erase its entry if the count becomes zero. A zero-valued record still contributes to map size. This is a representation rule for an active bag; a real record with a score or balance of zero may need to remain in other tasks.

C++23
// Complete C++23 program. Input: q commands.
// 1 x: add one. 2 x: remove one if present. 3: print distinct count.
#include <iostream>
#include <map>
int main() {
    int q;
    std::cin >> q;
    std::map<int, int> frequency;
    while (q--) {
        int type;
        std::cin >> type;
        if (type == 3) {
            std::cout << frequency.size() << '\n';
            continue;
        }
        int x;
        std::cin >> x;
        if (type == 1) ++frequency[x];
        else {
            auto it = frequency.find(x);
            if (it != frequency.end()) {
                --it->second;
                if (it->second == 0) frequency.erase(it);
            }
        }
    }
}

Each test case owns its state

Create local containers inside solve(), or explicitly reset every piece of state before the next case. Cases [1, 2] and [2, 3] each have two distinct keys; a shared uncleared set incorrectly reports three in the second case.

Add work across cases. With total input length N, an upper bound for set construction is O(T + N log(N + 1)); peak storage follows the largest live case. Passing a map by value to every query can add O(qd) copying independently of its fast lookup.

Use a boundary checklist with a reason

Test empty collections where allowed, one item, all equal, all distinct, absent keys below/between/above stored keys, and deleting the final item. For maps, include mapped zero and repeated assignments. For ranks, test negative, first, last, and exactly one-past-last requests.

If too many copies disappear, inspect the multiset erase overload. If size grows on queries, inspect subscript. If an output order changes, inspect hash traversal. If samples pass but large tests stall, count duplicate runs, iterator walks, container copies, and output volume. Explain the invariant before changing the container.

Word frequency map

Split on whitespace. Keys are case-sensitive; punctuation stays attached. Displayed in sorted key order like std::map<string, int>.

code3
learn2
solve1

6 words · 3 distinct keys

Guided simulation · Change the inputs to test your understanding.

Pause & predict

Add 7, add 7, remove 7, remove 7 in an active frequency map. What should the distinct counts be?

Choose an answer
Try it yourself

Turn the idea into code

A command parser always reads type and x, but command 3 has no x. Explain the bug and how the complete program avoids it.

Give me a hint

Input is a stream; consuming an extra integer steals part of the next command.

Show the explained solution

Reading x after command 3 consumes the next command type and misaligns all subsequent input. Handle type 3 immediately and continue; only commands 1 and 2 read an x. The operation contract controls both the container update and input parsing.

Your notes

Ready for the next idea?

Mark complete when you can explain it yourself.

From a problem to a programIdentify the input, output, and constraints, then translate a small plan into C++.Variables, types, and remembered valuesChoose a representation, initialize it, and understand what assignment really changes.Arithmetic without surprisesPredict division and remainder, widen before multiplication, and format decimal answers.Conditions and logical decisionsBuild exclusive categories, combine comparisons, and protect operations with short-circuit logic.Optional: other ways to chooseRecognize switch for exact choices and the conditional operator for choosing a value.For loops: make repetition preciseTrace initialization, condition, body, and update—and avoid an extra iteration.While, do-while, and stopping rulesChoose a loop from its stopping condition and read the exact input format.Break, continue, and early answersDistinguish leaving a loop from skipping one iteration, without losing required input.Five patterns worth understandingUse sums, counts, best-so-far candidates, products, and flags to process a stream.Nested loops: rows and columnsTranslate a shape into two loop roles and count the total work.Take a number apart, one digit at a timeUse remainder and division to process decimal digits, including zero.Multiple cases and a debugging mindsetCombine the patterns, isolate each case, and test the boundaries that can break your idea.Arrays: give every value a placeUnderstand indices, initialization, capacity, active length, and the first safe array loop.Scan, count, search, and compareDistinguish values from positions and preserve the exact tie rule a problem asks for.Change a sequence without losing itUpdate, copy, compare, reverse, and inspect neighbours using the correct bounds.Matrices: think in two coordinatesTraverse tables, total rows and columns, inspect diagonals, and protect grid neighbours.Characters become stringsSeparate characters from numbers, then safely inspect and edit managed text.Read the text the problem actually givesChoose words or full lines, preserve empty cases, and reset only the state that needs it.Scan text: count, filter, transformBuild a result from matching characters without losing leading zeros or skipping shifted text.Join, compare, and find textLearn content comparison, lexicographical order, substring counts, and the not-found sentinel.