trie树

Posted KaaaterinaX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了trie树相关的知识,希望对你有一定的参考价值。

这dp实在是d不动了,那我先学几个数据结构!

Trie树可以用于快速存储和查找字符串集合。
而且代码非常简短,以下是一个最基础的trie树结构。

随便揪一张图片:

基础题的代码实现:
Shortest Prefixes

const int maxn=2e4+7;
int s[maxn][26];//s[i]['a'-'a']=v,i为当前节点编号,s[i]['a']为‘a’的子节点的编号
int idx=0;
int cnt[maxn];//每个节点出现了多少次
void insert(string x)
    int p=0;
    for(int i=0;i<x.size();i++)
        if(!s[p][x[i]-'a'])
            s[p][x[i]-'a']=++idx;
        
        p=s[p][x[i]-'a'];
        cnt[p]++;
    

void query(string x)
    int p=0;
    string ans;
    for(int i=0;i<x.size();i++)
        ans+=x[i];
        p=s[p][x[i]-'a'];
        if(cnt[p]==1)
            break;
    
    cout<<x<<' '<<ans<<endl;

string x[2000];
int main()
    //建立字典树
    string a;
    int id=0;
    while(cin>>a)
        insert(a);
        x[++id]=a;
//        if(id==12)
//            break;
//        
    
    for(int i=1;i<=id;i++)
        query(x[i]);
    

(字典树结构是真的简单易懂,但是题目可以出得很有意思)
比如说这个题:
3485. 最大异或和
(好久之前的acwing每日一题╮( ̄▽ ̄"")╭)

其实学了字典树之后这个题超级简单的!
基本思路就是求出异或前缀和,在滑动窗口内查询异或最大值即可。建树的时候加一个删除操作就行。

ac代码:

//可以删除元素的trie树
const int maxn=1e5+7;
ll a[maxn];
ll sum[maxn];//异或前缀和
int s[31*maxn][2];
int cnt[31*maxn];//数每个节点的cnt,方便删除
int idx=0;
void build(ll x)
    //进行二进制拆分,构造字典树
    //从高位到低位
    int p=0;
    for(int i=32;i>=0;i--)
        int t=(x>>i)&1;
        if(!s[p][t])
            s[p][t]=++idx;
        
        p=s[p][t];
        cnt[p]++;
    

//删除操作
void elim(ll x)
    int p=0;
    for(int i=32;i>=0;i--)
        int t=(x>>i)&1;
        p=s[p][t];
        cnt[p]--;
    

ll query(ll x)
    int p=0;
    int ans=0;
    for(int i=32;i>=0;i--)
        ll t=(x>>i)&1;
        if(t==1)
            //要找该位为0的
            if(cnt[s[p][0]]!=0)
                p=s[p][0];
                ans+=1<<i;
            
            else
                p=s[p][1];
            
        
        else
            //要找该位为1的
            if(cnt[s[p][1]]!=0)
                p=s[p][1];
                ans+=1<<i;
            
            else
                p=s[p][0];
            
        
    
    return ans;

int main()
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
        sum[i]=sum[i-1]^a[i];
    
    //滑动窗口
    ll res=0;
    for(int i=0;i<=m;i++)
        //必须要将sum[0]加入字典树
        build(sum[i]);
        res=max(res,query(sum[i]));
    
    int l=0;
    int r=m+1;
    while(r<=n)
        build(sum[r]);
        if(r-l>m)
            elim(sum[l]);//左边界不再符合条件,窗口向右滑动
            l++;
        
        res=max(res,query(sum[r]));
        r++;
    
    cout<<res<<endl;



以上是关于trie树的主要内容,如果未能解决你的问题,请参考以下文章

Trie字典树 静态内存

XJOI 异或 (Trie树)

Immediate Decodability[UVA644](Trie树入门)

luoguP6623 [省选联考 2020 A 卷] 树(trie树)

HDU4825 Xor Sum(贪心+Trie树)

ACM算法目录