洛谷 P8306 【模板】字典树


字典树 (Trie) - OI Wiki

【数据结构】字典树TrieTree图文详解_Avalon Demerzel的博客-CSDN博客

建议先看一看上面那两个网站,不透彻的可以再看我的理解一下。

由于字典树的每一个节点都是有用的,都有可能是一个单词的结尾,所以需要给每个节点打上编号,所以字典树所占的内存会非常大。

第一维大小可以直接用字符串最长长度来测试(不够再扩大)

最重要的是二维数组的含义

根据打上编号的字典树结构我们可以发现,每一个节点下面都可以跟26种情况,为了方便迭代查阅,定义二维数组为 t[当前节点编号][连接的字母]=子节点编号 

即有 t[子节点编号][连接的字母]=子节点编号的编号,直接套用自己即可。

如果对应有编号,那就说明连上了,没有编号,那就是没连着。


这道题有大写字母,小写字母,数字,一共26+26+10=62种。

将其映射到二维数组中。

int getNum(char c){
    if(c>='a' and c<='z')return c-'a';
    else if(c>='A' and c<='Z')return c-'A'+26;
    else return c-'0'+52;
}

根据二维数组含义实现插入。

inline void insert(){
    int now=0;//从根节点开始往下连接
    for(int i=0;i<s.length();++i){
        int k= getNum(s[i]);//得到映射
        if(!t[now][k])t[now][k]=++idx;//没有这个字母的话,新建一个节点
        now=t[now][k];//往下搜
        cnt[now]++;//记录所有前缀,此题要用
    }
}

和插入基本一样的查找。

int find(){
    int now=0;
    for(int i=0;i<s.length();++i){
        int k= getNum(s[i]);
        if(!t[now][k])return 0;
        now=t[now][k];
    }
    return cnt[now];
}

最后,由于初始化一直在用memset一直导致TLE。

原因应该是需要被初始化的空间(编号范围)远小于N,如果用memset去初始化所有空间就会超时。

所以这道题的初始化应该用for来手动赋值(for的手动赋值和memset在汇编上实现一致,但是for的范围更小,所以此处速度比memset快的多)

参考:memset()比C中的循环效率更高吗? |

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=3e6+10;

inline void betterCinCout(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
}
int getNum(char c){
    if(c>='a' and c<='z')return c-'a';
    else if(c>='A' and c<='Z')return c-'A'+26;
    else return c-'0'+52;
}
int T,n,q,t[N][63],idx,cnt[N];
string s;
inline void insert(){
    int now=0;//从根节点开始往下连接
    for(int i=0;i<s.length();++i){
        int k= getNum(s[i]);//得到映射
        if(!t[now][k])t[now][k]=++idx;//没有这个字母的话,新建一个节点
        now=t[now][k];//往下搜
        cnt[now]++;//记录所有前缀,此题要用
    }
}
inline void init(){
    for(int i=0;i<=idx;++i)
        for(int j=0;j<=62;++j)
            t[i][j]=0;
    for(int i=0;i<=idx;++i)
        cnt[i]=0;
    idx=0;
}
int find(){
    int now=0;
    for(int i=0;i<s.length();++i){
        int k= getNum(s[i]);
        if(!t[now][k])return 0;
        now=t[now][k];
    }
    return cnt[now];
}

int main(){
    betterCinCout();

    cin>>T;
    while(T--){
        init();

        cin>>n>>q;
        for(int i=1;i<=n;++i){
            cin>>s;
            insert();
        }

        for(int i=1;i<=q;++i){
            cin>>s;
            cout<<find()<<endl;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_17807067/article/details/129827871
今日推荐