Trie tree summary and usage

trie tree (usage and summary)

-Nanchang Institute of Technology Training Team

  • What is a trie tree (find a picture)

    Insert picture description here
    -This is the basic principle of trie tree storage.

    It is to store each character in the form of a tree, and save the node to search.
    This approach is very efficient (it can be seen that because of the high repetition rate of characters)

    -The role of trie tree

    1 Store characters and search for characters (very efficient, the most basic usage)
    2 Find whether the two-character
    prefix and suffix satisfy the string (very important, but also the core usage) 3 Find the same prefix or suffix in the prefix or suffix
    4 XOR pair (Difficult, I haven't learned it yet, don't ask, ask is that IQ is too low (;'⌒`))

      qwq 肯定很疑惑为什么不用KMP大法。(0.0)
    

    (Of course KMP can also be used, but when the number is large, it is very slow. It is sad to enumerate one by one)

    -Template provided

    The important link is here, how to implement it in code?

  • The first is storage (insert trie tree)

void insert(char *str)
{
    
    
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
    
    
        int u = str[i] - 'a';
        if (!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}
  • Second search character
// 查询字符串
bool query(char *str)
{
    
    
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
    
    
        int u = str[i] - 'a';
        if (!son[p][u]) return false;
        p = son[p][u];
    }
    return cut[p];
}

These are the two main ways to play, and the rest is to maintain the trie tree by yourself.

  • Come to a template question

Insert picture description here

#include<iostream>

using namespace std;
const int N=1e6+10;
int son[N][26],cut[N],idx;
string op,str;
void insert(string str){
    
    
    int p=0;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'a';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cut[p]++;
}
int query(string str){
    
    
    int p=0;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'a';
        if(!son[p][u]) return 0;
        p=son[p][u];
    }
    return cut[p];
}
int main(){
    
    
    int n;
    cin>>n;
    while(n--){
    
    
        cin>>op>>str;
        if(op=="I") insert(str);
        else cout<<query(str)<<endl;
    }
}

This is the usage of trie tree efficient storage. (Be sure to understand, don’t memorize it, it’s useless)

  • For example, a simple template question

Insert picture description here

  • Code (we use the repeat array to maintain to see if this has been clicked, of course, you can also directly use the cut array 0-0)
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
const int N=1e6+10;
int son[N][26],cut[N],repeat[N],idx;
int n,m;
void insert(string str){
    
    
    int p=0;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'a';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cut[p]++;
}
int query(string str){
    
    
    int p=0;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'a';
        if(!son[p][u]) return 0;
        p=son[p][u];
    }
    return p;
}
int main(){
    
    
    cin>>n;
    while(n--){
    
    
        string str;
        cin>>str;
        insert(str);
    }
    cin>>m;
    while(m--){
    
    
        string str;
        cin>>str;
        if(!query(str)) puts("WRONG");
        else if(cut[query(str)]&&!repeat[query(str)]++) puts("OK");
        else puts("REPEAT");
    }
}

There must be a lot of doubts for beginners, such as how to maintain capitalization and letters
to speak with specific topics (generally you can directly open to 58, no special judgment is required, if there is a number, special judgment is made)

Insert picture description here

  • Code (merge sort count reverse pair + trie tree storage + cut array record position)
// trie 树+归并排序
#include<iostream>
#include<string>
using namespace std;
const int N=5e5+10;
int son[N][58],cut[N],idx;
int n,a[N],b[N];
long long res=0;
void insert(string str,int k){
    
    
    int p=1;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'A';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cut[p]=k;
}
void query(string str,int k){
    
    
    int p=1;
    for(int i=0;i<str.size();i++){
    
    
        int u=str[i]-'A';
        p=son[p][u];
    }
    a[k]=cut[p];
}
void merge_sort(int l,int r){
    
    
    if(l>=r) return ;
    int mid=l+r>>1;
    merge_sort(l,mid),merge_sort(mid+1,r);
    int k=0,i=l,j=mid+1;
    while(i<=mid&&j<=r)
        if(a[i]<=a[j]) b[k++]=a[i++];
        else b[k++]=a[j++],res+=mid-i+1;
    while(i<=mid) b[k++]=a[i++];
    while(j<=r) b[k++]=a[j++];
    for(i=l,j=0;i<=r;i++,j++) a[i]=b[j];
}
int main(){
    
    
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        string str;
        cin>>str;
        insert(str,i);
    }
    for(int i=1;i<=n;i++){
    
    
        string str;
        cin>>str;
        query(str,i);
    }
    merge_sort(1,n);
    cout<<res;
    return 0;
}

Here is a question for summing prefixes

Insert picture description here

  • Code (Ability is constantly brushing questions to improve)

We use the cut array to determine whether the prefix is ​​satisfied
(remind that it is a.size()-1, not a.size() when searching)

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int N=1e5+10;
int son[N][10],cut[N],idx;
string str[N];
int T;
void init(){
    
    
    memset(son,0,sizeof(son));
    memset(cut,0,sizeof(cut));
    idx=0;
}
void insert(string a){
    
    
    int p=0;
    for(int i=0;i<a.size();i++){
    
    
        int u=a[i]-'0';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cut[p]++;
}
bool find(string a){
    
    
    int p=0;
    for(int i=0;i<a.size()-1;i++){
    
    
        int u=a[i]-'0';
        p=son[p][u];
        if(cut[p]) return true;
    }
    return false;
}
int main(){
    
    
    cin>>T;
    while(T--){
    
    
        init();
        int n;
        cin>>n;
        for(int i=0;i<n;i++) cin>>str[i],insert(str[i]);
        bool flag=false;
        for(int i=0;i<n;i++)
        if(find(str[i])){
    
    
            flag=true;
            break;
        }
        if(flag) puts("NO");
        else puts("YES");
    }
    return 0;
}

Finally, a suffix question

Insert picture description here
Of course, this question is very simple. The range of N is only 200, but when the range of N becomes larger, the tried tree can still be solved (mainly because the question is not found)

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int son[N][59],cut[N],idx;
int n,len;
void init(){
    
    
    memset(son,0,sizeof(son));
    memset(cut,0,sizeof(cut));
    idx=0;
    len=0;
}
void insert(string a){
    
    
    int p=0;
    for(int i=a.size()-1;i>=0;i--){
    
    
        int u=a[i]-'A';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
        cut[p]++;
    }
}
int query(string a){
    
    
    int p=0;
    for(int i=a.size()-1;i>=0;i--){
    
    
        int u=a[i]-'A';
        p=son[p][u];
        if(cut[p]==n) len++;
        else break;
    }
    return len;
}
int main(){
    
    
    while(cin>>n,n){
    
    
        init();
        string a,b;
        cin>>b;insert(b);
        for(int i=1;i<n;i++){
    
    
            cin>>a;insert(a); 
            if(a.size()<b.size()) b=a;
        }
        cout<<b.substr(b.size()-query(b))<<endl;
    }
    return 0;
}

The topic is the core of code training. I hope everyone can work
hard together. Mengxin pays tribute to ORZ. Click a thumbs-up (find the title, very hard)
. I learned to add XOR pairs. Don’t blame me, my ability is limited. Mengxin kowtows.

Guess you like

Origin blog.csdn.net/m0_52361859/article/details/112768082