Cod sursa(job #3299554)

Utilizator OvidRata Ovidiu Ovid Data 8 iunie 2025 13:42:15
Problema Aho-Corasick Scor 55
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.24 kb
#include<bits/stdc++.h>
using namespace std;

//#pragma GCC optimize("O3,unroll-loops")
//#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")


string numeFisier="ahocorasick";
ifstream fin(numeFisier+".in"); ofstream fout(numeFisier+".out");
#define cin fin
#define cout fout


#define INIT  ios_base :: sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define mp make_pair
#define pb push_back
#define ft first
#define sc second
#define ll long long
#define pii pair<int, int>
#define count_bits __builtin_popcount
//#define int ll




int t, n, m, k, a[300010], q, l, r;


string text;
string pattern[101];
int occurrences[101];



class AhoCorasickAutomaton{
    public: 

    class Vertex{
        public:
            Vertex* suffLink=nullptr;
            Vertex* pchr[26];
            vector<int> wordIndexes;

            int lazy=0;
            Vertex* exitLink=nullptr;
            bool checkedExit = false;
            int inDegree = 0;
    };

    // set<Vertex*> s;

    // map<Vertex*, int> h;

    Vertex *root = new Vertex();

    void addWordTrie(Vertex* Root,string s, int index){
        
        Vertex* node = Root;

        for(int i=0; i<s.length(); i++){
            auto parent = node;
            if( !node->pchr[ s[i] - 'a' ] ){
                node->pchr[ s[i] - 'a' ] = new Vertex();
                node->pchr[ s[i]-'a' ]->suffLink=root;
            }
            node = node->pchr[ s[i]-'a' ];
        }
        node->wordIndexes.pb(index);


    }


    void makeSuffixLinks(Vertex* root, int depth){
        
        // int sz = s.size();
        // s.insert(root);
        // if(s.size()>sz){
        //     h[root] = s.size();
        // }
        
        for(char c='a'; c<='z'; c++){
            
            if( !root->pchr[ c-'a' ] )continue;
            
            if(depth>0){
                Vertex* node = root->pchr[c-'a'];
                node->suffLink = root->suffLink;

                while( !node->suffLink->pchr[ c - 'a' ] && (node->suffLink->suffLink != node->suffLink) ){
                    node->suffLink = node->suffLink->suffLink;
                }

                if( node->suffLink->pchr[ c-'a' ] ){
                    node->suffLink = node->suffLink->pchr[ c-'a' ];
                }
            }

            makeSuffixLinks( root->pchr[c-'a'], depth+1 );
        }

        
    }
    

    void dfsSuffixLinks(Vertex* root){
            auto node = root;
            if(root->checkedExit){
                return;
            }
            if(!node->suffLink->checkedExit){
                dfsSuffixLinks(node->suffLink);
            }

            node->checkedExit=true;
            node->exitLink = node->suffLink->exitLink;

            if(!node->suffLink->wordIndexes.empty()){
                node->exitLink = node->suffLink;
            }

    }

    void makeExitLink(Vertex * root){
        dfsSuffixLinks(root);

        for(char c='a'; c<='z'; c++){
            
            if( !root->pchr[ c-'a' ] )continue;
            
            
           
            makeExitLink( root->pchr[c-'a'] );
        }
        
        // cout<<h[root]<<": "<<h[root->suffLink]<<" - "<<h[root->exitLink]<<" - ";
        // for(char c='a'; c<='z'; c++){
        //     if( root->pchr[c-'a' ] ){
        //         cout<<"("<<c<<" + "<<h[root->pchr[c-'a']]<<") ";
        //     }
        // }
        // cout<<"\n";
    }

    
    void propagateLazy(){
        


        queue<Vertex*> q;

        stack<Vertex*> s;

        s.push(root);
        
        while(!s.empty()){
            auto node = s.top();
            if( !node->wordIndexes.empty() ){
                if(node->exitLink){
                    node->exitLink->inDegree++;
                }
                q.push(node);
            }
            s.pop();
            for(char c='a' ;c<='z'; c++){
                if( node->pchr[c-'a'] ){
                    s.push(node->pchr[ c-'a' ]);
                }
            }
        }


        while(!q.empty()){
            auto f = q.front();
            q.pop();
            if(f->inDegree>0){
                continue;
            }

            if(f->exitLink){
                int sum = 0;
                for(int index:f->wordIndexes){
                    sum+=occurrences[index];
                }
                f->exitLink->lazy+=f->lazy+sum;
                f->exitLink->inDegree--;
                if(f->exitLink->inDegree==0){
                    q.push(f->exitLink);
                }
            }

            


            for(auto index:f->wordIndexes){
                occurrences[index]+=f->lazy;
            }
            f->lazy=0;
        }

    }


    void searchText(string &text, int occurrences[]){
        Vertex* node = root;

        for(int i=0; i<text.length(); i++){
            char c = text[i];
            if( node->pchr[ c-'a' ] ){
                node = node->pchr[ c-'a' ];
            }
            else{
                while( !node->pchr[ c - 'a' ] && node->suffLink!=node ){
                    node = node->suffLink;
                }
                if(node->pchr[ c-'a' ]){
                    node = node->pchr[c-'a'];
                }
            }
            for(auto index:node->wordIndexes){
                occurrences[index]++;
            }
            if( node->wordIndexes.empty() ){
                if( node->exitLink ){
                    node->exitLink->lazy++;
                }
            }
        }


        propagateLazy();
    }

} ahoCorasick;




int32_t main(){
    INIT

    cin>>text;
    cin>>k;
    for(int i=1; i<=k; i++){
        cin>>pattern[i];
    }
    
    ahoCorasick.root->suffLink = ahoCorasick.root;
    ahoCorasick.root->checkedExit = true;

    for(int i=1; i<=k; i++){
        ahoCorasick.addWordTrie(ahoCorasick.root, pattern[i], i);
    }
    ahoCorasick.makeSuffixLinks(ahoCorasick.root, 0);
    ahoCorasick.makeExitLink(ahoCorasick.root);

    ahoCorasick.searchText(text, occurrences);

    for(int i=1; i<=k; i++){
        cout<<occurrences[i]<<"\n";
    }


    return 0;
}