trie
普通 trie
这就是一棵 trie 树,有很多的节点,但是关键字并不在节点上,而是在路径上,这是一个易错点。
一般的运用是开一棵关于字符的 trie 或者是 01trie。
我们可以来看几道题目。
- P3879
字符串中的 trie
题目大意是给定
最暴力的想法是对于每一个询问,都暴力跑一遍
很明显会超时,考虑使用字典树。
建
然后查询的时候就可以通过枚举每一棵字典树快速检索答案。
复杂度是
那么如何标记每一个单词的出现情况呢?
我们定义一个用来标记节点的数组
一个常用的思路,固定住一端,通过求符合条件的另一端达到计数的目的。
很自然的想到固定住
现在讲问题转化为如何快速求符合条件的
考虑建一棵有关
由于字典树是 01 的形式呈现,不妨把
思考一个小问题,如何判断一个数大于等于
接着字典树说,我们假设当前已经找到了第
如果
否则的话只能检索
最后检索完毕时,因为可以大于等于,所以还要加上
空间该开多大呢?这也是字典树中一个常见的问题,注意到有
贴一下 trie 的代码。
struct trie{
int nxt[N*30][2],sz[N*30],idx;
void insert(int x){
int p=0;
for(int i=30;~i;i--){
int ch=x>>i&1;
if(!nxt[p][ch]) nxt[p][ch]=++idx;
p=nxt[p][ch],sz[p]++;
}
}
int query(int x){
int p=0,res=0;
for(int i=30;~i;i--){
int ch=x>>i&1,ck=k>>i&1;
if(ck) p=nxt[p][ch^1];
else res+=sz[nxt[p][ch^1]],p=nxt[p][ch];
if(!sz[p]) return res;
}
return res+sz[p];
}
}T;
trie 的合并
这个没有什么好讲的,跟其它的形式差不多。
int merge(int x,int y){
if(!x || !y) return x+y;
sz[x]+=sz[y],nxt[x][0]=merge(nxt[x][0],nxt[y][0]),nxt[x][1]=merge(nxt[x][1],nxt[y][1]);
return x;
}
trie 的全局加1
在二进制下,权值加 1,实际上就是交换了左右的儿子,但是有一点很特殊,但是 1 会进位,所以仍然需要递归处理 nxt[p][0]
void addall(int p){
swap(nxt[p][0],nxt[p][1]);
if(nxt[o][0]) addall(nxt[p][0]);
}
可持久化 trie
可持久化 trie 是一种常用的东西,它可以很方便的记录历史值,并更新,它的主要原理是:对于每一次修改,只会修改一部分,其它的可以继承前面的。下面以一道例题展开讲述。
- P4735
题目所求可以转化位
而
因此我们需要找到最大的
我们可以转化为前缀形式,即通过两棵字典树来计算
那么即用
但是发现空间不够开,所以可以考虑可持久化,每次的修改都是一条链。
贴一下字典树的代码
struct trie{
int idx,nxt[30000005][2],sz[30000005];
void insert(int x,int y,int z){
for(re int i=28;~i;i--){
int ch=z>>i&1;
if(ch){
if(!nxt[x][1]) nxt[x][1]=++idx;
nxt[x][0]=nxt[y][0],x=nxt[x][1],y=nxt[y][1];
}
else{
if(!nxt[x][0]) nxt[x][0]=++idx;
nxt[x][1]=nxt[y][1],x=nxt[x][0],y=nxt[y][0];
}
sz[x]=sz[y]+1;
}
}
int query(int x,int y,int z){
int res=0;
for(re int i=28;~i;i--){
int ch=z>>i&1;
if(sz[nxt[x][!ch]]-sz[nxt[y][!ch]]) res+=(1<<i),x=nxt[x][!ch],y=nxt[y][!ch];
else x=nxt[x][ch],y=nxt[y][ch];
}
return res;
}
}T;
int main(){
for(re int i=1;i<=n;i++) s[i]=qr()^s[i-1],rt[i]=++T.idx,T.insert(rt[i],rt[i-1],s[i]);
while(m--){
char op;
int l,r,x;
cin>>op;
if(op=='A') n++,rt[n]=++T.idx,s[n]=s[n-1]^qr(),T.insert(rt[n],rt[n-1],s[n]);
else{
l=qr()-1,r=qr()-1,x=qr();
if(!l) qw(max(s[n]^x,T.query(rt[r],rt[0],s[n]^x)));
else qw(T.query(rt[r],rt[l-1],s[n]^x));
putchar('\n');
}
}
return 0;
}