可持久化Trie模板

如果你了解过可持久化线段树(例如 : 主席树 )、那么就比较好去可持久化 Trie

可持久化 Trie 和主席树真的很类似,都是通过为每个前缀or节点存储一颗 Trie

然后再通过减法的方式来达到某一区间或者某一历史版本的状态

这里只给出模板、关于这个算法的学习、推荐 ==> Click here

模板 :

#include<bits/stdc++.h>
using namespace std;
const int maxNode = 1e6 + 10;
const int maxn = 1e5 + 10;
int root[maxn];///每颗Trie的根节点编号
int sz[maxNode];///每个节点被添加or访问了多少次
int ch[maxNode][2];///静态指针、指向每个节点的01边指向的节点
int totNode = 0;///用于新开节点编号、多测问题别忘初始化

///静态开辟节点
int newNode()
{
    memset(ch[totNode], 0, sizeof(ch[totNode]));
    sz[totNode] = 0;
    return totNode++;
}

///F是将要被继承的树、C是当前新增的树、val就是即将被添加到C这棵树上的值
inline void Insert(int F, int C, int val)
{
    F = root[F], C = root[C];
    for(int i=15; i>=0; i--){
        int bit = (val>>i) & 1;
        if(!ch[C][bit]){
            ch[C][bit] = newNode();
            ch[C][!bit] = ch[F][!bit];
            sz[ ch[C][bit] ] = sz[ ch[F][bit] ];
        }
        C = ch[C][bit], F = ch[F][bit];
        sz[C]++;
    }
}

///查询函数可以说是很多变了
///可持久化Trie的查询并不是很模板的一个东西
///所以请务必理解可持久化Trie的原理再来运用这个模板
///以下的查询函数是 HDU 4757 的查询函数
int Query(int A, int B, int val)
{
    int lca = LCA(A, B);
    int lcaAns = arr[lca]^val;
    A = root[A], B = root[B], lca = root[lca];
    int ret = 0;
    for(int i=15; i>=0; i--){
        int bit = (val>>i) & 1;
        if(sz[ch[A][!bit]] + sz[ch[B][!bit]] - 2 * sz[ch[lca][!bit]] > 0){
            ret += 1<<i;
            A = ch[A][!bit];
            B = ch[B][!bit];
            lca = ch[lca][!bit];
        }else A = ch[A][bit], B = ch[B][bit], lca = ch[lca][bit];
    }

    return max(ret, lcaAns);
}

///这个查询函数则对应 BZOJ 3261
int query(int x, int y, int val)
{
    int ret = 0;
    for(int i=Bit; i>=0; i--){
        int c = (val>>i) & 1;
        if(sum[ch[y][!c]] - sum[ch[x][!c]] > 0)
            ret += (1<<i),
            y = ch[y][!c],
            x = ch[x][!c];
        else x = ch[x][c], y = ch[y][c];
    }
    return ret;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Rubbishes/p/9141345.html