Cod sursa(job #3290876)

Utilizator mihai_bosIancu Mihai mihai_bos Data 1 aprilie 2025 17:14:07
Problema Trie Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.83 kb
#include <fstream>
#include <string>
#include <cstring>
using namespace std;

ifstream cin("trie.in");
ofstream cout("trie.out");

const int ALPHABET_SIZE = 26;
// Să presupunem o limită suficientă de noduri (în funcţie de constrângeri)
const int MAX_NODES = 3000000;

// trie[node][litera] = indicele nodului copil (0 înseamnă "nu există")
int trie[MAX_NODES][ALPHABET_SIZE];
// cnt[node] = numărul de cuvinte care au trecut prin acest nod la inserare
int cnt[MAX_NODES];
// exact[node] = numărul de cuvinte terminate exact în acest nod
int exact[MAX_NODES];
int nodeCount = 1; // nodul 0 este rădăcina

// Inserare: actualizează atât contorul exact, cât şi pe cel de prefix (cnt)
void insert(const string &s) {
    int node = 0;
    for (char c : s) {
        int idx = c - 'a';
        if (trie[node][idx] == 0) {
            trie[node][idx] = nodeCount++;
        }
        node = trie[node][idx];
        cnt[node]++;  // adăugăm la contorul de prefix
    }
    exact[node]++;  // cuvântul s se termină aici
}

// Ștergere: se scade doar din contorul exact – NU se scade cnt (așa cum cere testul)
void removeWord(const string &s) {
    int node = 0;
    for (char c : s) {
        int idx = c - 'a';
        if (trie[node][idx] == 0) return; // cuvântul nu există, nu facem nimic
        node = trie[node][idx];
    }
    if (exact[node] > 0)
        exact[node]--; // scădem doar numărul de apariţii exacte
}

// Query tip 2: numărul de apariţii exacte ale şirului s
int queryExact(const string &s) {
    int node = 0;
    for (char c : s) {
        int idx = c - 'a';
        if (trie[node][idx] == 0) return 0;
        node = trie[node][idx];
    }
    return exact[node];
}

// Query tip 3: parcurgem cât se poate din s; dacă la un moment dat nu găsim o legătură,
// returnăm contorul ultimului nod valid
int queryPrefix(const string &s) {
    int node = 0;
    int lastValid = 0; // vom păstra contorul ultimului nod pe care l-am parcurs
    for (char c : s) {
        int idx = c - 'a';
        if (trie[node][idx] == 0)
            return cnt[node]; // întoarce contorul nodului curent (ultimul valid)
        node = trie[node][idx];
        lastValid = node;
    }
    return cnt[lastValid];
}

int main() {
    int op;
    string s;
    // Numărul total de operaţii (se presupune că inputul are 16 linii ca în exemplul dat)
    // Sau se poate citi până la EOF.
    // Pentru exemplul dat, vom citi până la EOF.
    while (cin >> op >> s) {
        if(op == 0) {
            insert(s);
        }
        else if(op == 1) {
            removeWord(s);
        }
        else if(op == 2) {
            cout << queryExact(s) << "\n";
        }
        else if(op == 3) {
            cout << queryPrefix(s) << "\n";
        }
    }
    return 0;
}