可持久化Trie
参考可持久化线段树的思想,修改的时候先直接复制,再对需要修改的点新建节点
可持久化Trie也是同样的做法,假设现在需要在原本Trie的基础上插入一个字符串
先把上个Trie的对应节点信息复制过来,对(son[ch])新建节点
void insert(int x,int y,char*st){
int l=strlen(st);
for(int i=0;i<l;i++){
int k=st[i]-'a';t[x].ch[k]=++tot;//新建
x=t[x].ch[k];y=t[y].ch[k];
t[x]=t[y];t[x].v++;//复制并更新
}
}
查询先确定rt,然后类似Trie一样直接把字符串丢进去查即可
int query(int u,char*st){
int l=strlen(st);
for(int i=0;i<l;i++){
int k=st[i]-'a';
if(!t[u].ch[k])return 0;
u=t[u].ch[k];
}
return t[u].v;
}
或者你二进制Trie是这么查的(下面是在一个区间中查异或max的模板)
int query(int x,int y,int num){
int res=0;
for(int i=24;i>=0;i--){
int k=num>>i&1^1;
if(t[y].ch[k]-t[x].ch[k]==0)k^=1;//没有能使该位为1的数
else res|=(1<<i);
x=t[x].ch[k];y=t[y].ch[k];
}
return res;
}
空间=Trie的空间*log
主要是一些字符串或者序列异或的题目中使用,注意到和主席树一样是可减的
常见套路
- 路径问题就维护根到i的前缀Trie,然后把u,v,lca拿出来搞一搞
- 子树问题求dfn,rk,直接按dfn跑一遍前缀Trie,之后当区间处理