Cod sursa(job #3347870)

Utilizator altomMirel Fanel altom Data 18 martie 2026 17:23:00
Problema Trie Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.39 kb
#include <bits/stdc++.h>
using namespace std;

ifstream fin("trie.in");
ofstream fout("trie.out");

struct trie_node {
    int frec;                 // number of words that end exactly here
    int cnt;                  // number of words in subtree rooted here
    trie_node* copii[26];

    trie_node() : frec(0), cnt(0) {
        for (int i = 0; i < 26; ++i) copii[i] = nullptr;
    }
};

trie_node* rad = new trie_node;

inline int idx_of(char c) {
    return c - 'a';
}

void adauga(const string &s) {
    trie_node* nod = rad;
    nod->cnt++; // root counts this insertion
    for (char c : s) {
        int idx = idx_of(c);
        if (idx < 0 || idx >= 26) return; // defensive (shouldn't happen per statement)
        if (nod->copii[idx] == nullptr)
            nod->copii[idx] = new trie_node;
        nod = nod->copii[idx];
        nod->cnt++;
    }
    nod->frec++;
}

void sterge(const string &s) {
    // first walk the path while recording nodes + indices
    trie_node* nod = rad;
    vector<pair<trie_node*, int>> path; // (node, idx used to go to child)
    // decrement root's cnt immediately (we know the word exists by problem statement)
    nod->cnt--;
    for (char c : s) {
        int idx = idx_of(c);
        // defensive checks (should not trigger with valid input)
        if (idx < 0 || idx >= 26) return;
        trie_node* child = nod->copii[idx];
        if (child == nullptr) return; // defensive: word not present (shouldn't happen)
        path.emplace_back(nod, idx);
        nod = child;
        nod->cnt--;
    }
    // nod now points to final node for the word
    if (nod->frec > 0) nod->frec--;
    else return; // defensive: nothing to delete (shouldn't happen)

    // free nodes from leaf upward if they became unused (cnt==0 and frec==0)
    for (int i = (int)path.size() - 1; i >= 0; --i) {
        trie_node* parent = path[i].first;
        int idx = path[i].second;
        trie_node* child = parent->copii[idx];
        if (child && child->cnt == 0 && child->frec == 0) {
            // child subtree is empty: delete node and cut link
            delete child;
            parent->copii[idx] = nullptr;
        } else {
            // if child still has words in subtree, stop deleting upwards
            break;
        }
    }
}

int getCount(const string &s) {
    trie_node* nod = rad;
    for (char c : s) {
        int idx = idx_of(c);
        if (idx < 0 || idx >= 26) return 0;     // defensive
        if (nod->copii[idx] == nullptr) return 0;
        nod = nod->copii[idx];
    }
    return nod->frec;
}

int longestPref(const string &s) {
    trie_node* nod = rad;
    int cnt = 0;
    for (char c : s) {
        int idx = idx_of(c);
        if (idx < 0 || idx >= 26) break;
        if (nod->copii[idx] == nullptr) break;
        trie_node* child = nod->copii[idx];
        if (child->cnt == 0) break; // no existing word in that subtree
        nod = child;
        ++cnt;
    }
    return cnt;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    string s;
    while (fin >> t >> s) {
        switch (t) {
            case 0: adauga(s); break;
            case 1: sterge(s); break;
            case 2: fout << getCount(s) << '\n'; break;
            case 3: fout << longestPref(s) << '\n'; break;
            default: break;
        }
    }
    return 0;
}