杭电 2222

endd清零很重要,因为每次访问过后,有可能以后还会访问,不清零的话会导致重复相加。

#include <iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxm = 1000005;
const int maxc = 26;
const int maxn = 1000000 + 10;
struct Trie{
    int ch[maxm][maxc],num,f[maxm],last[maxm],val[maxm],cnt,endd[maxm],ans;
    void init(){
        memset(ch,0,sizeof(ch));
        memset(val,0,sizeof(val));
        memset(f,0,sizeof(f));
        memset(endd,0,sizeof(endd));
        num = 0; cnt = 0,ans = 0;
    }
    int idx(char c){
        int d = c - 'a';
        return d;
    }
    void Trie_insert(char* str){
        int u = 0;
        int len = strlen(str);
        for(int i = 0; i < len; i++){
            int c = idx(str[i]);
            if(!ch[u][c]){
                ch[u][c] = ++num;
            }
            u = ch[u][c];
        }
        val[u] = ++cnt;
        endd[u]++;
    }
    void dfa(){
        queue<int> que;
        for(int i = 0; i < maxc; i++){
            if(!ch[0][i]) continue;
            que.push( ch[0][i] );
        }
        while(!que.empty()){
            int r = que.front(); que.pop();
            for(int i = 0; i < maxc; i++){
                if(!ch[r][i]) {ch[r][i] = ch[ f[r] ][i]; continue;}    //小trick   ,含义是如果失配,则跳到不失配的点 或 0 节点去
                que.push(ch[r][i]);
                int v = f[r];
                while(v && !ch[v][i]) v = f[v];
                f[ ch[r][i] ] = ch[v][i];
               last[ ch[r][i] ] = val[ f[ch[r][i] ] ] ? f[ch[r][i] ] : last[ f[ ch[r][i] ] ];
            }
        }
    }
    int Trie_count(int j){
        if(j ){
            int v = endd[j];
            endd[j] = 0;
            return v + Trie_count(last[j]);

        }
        return 0;
    }
    int Trie_search(char* str){
        int u = 0,cnt = 0;
        for(int i = 0;str[i]; i++){                               //          这个最坑爹,如果把中间条件判断改成 i < strlen( str ),每次判断是否符合条件时都会调用一次这个函数,复杂度直接变成 n2 ,会超时,另外 strlen 返回无符号整形 ,若写成strlen - 2 则有可能生成一个很大的正数,很坑总之。。。。
            int c = idx( str[i] );
            /*if(ch[u][c]) u = ch[u][c];
            else{
                int v = f[u];
                while(v && !ch[v][c]) v = f[v];
                u = ch[v][c];
            }*/
           /* if(val[u]) cnt++;
            cnt += Trie_count(last[u]);*/
            while(u && !ch[u][c]) u = f[u]; // 有了上面的trick,不加这句话也可以
            u = ch[u][c];
            if(val[u])  cnt += Trie_count(u);
            else if(last[u])  cnt += Trie_count(last[u]);
        }
        return cnt;
    }
};
Trie trie;
int main()
{
    int T,d,n;
    char str[maxn];
   // freopen("123.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&d);
        trie.init();
        for(int i = 0; i < d; i++){
            scanf("%s",str);
            trie.Trie_insert(str);
        }
        trie.dfa();
        scanf("%s",str);
        n = trie.Trie_search(str);
        printf("%d\n",n);
    }

    return 0;
}
 

猜你喜欢

转载自blog.csdn.net/ehdhg13455/article/details/82193002