模板
const int MAX_N=301000;
int trie[MAX_N*32][2],latest[MAX_N*32];
int s[MAX_N],root[MAX_N],tot;
void insert(int k,int k1,int val,int i,int deep){
if(deep<0){
latest[k1]=i;
return;
}
int x=(val>>deep)&1;
if(k)
trie[k1][x^1]=trie[k][x^1];
trie[k1][x]=++tot;
insert(trie[k][x],trie[k1][x],val,i,deep-1);
latest[k1]=max(latest[trie[k1][0]],latest[trie[k1][1]]);
}
int ask(int k,int val,int deep,int limit){
if(deep<0)
return s[latest[k]]^val;
int x=(val>>deep)&1;
if(latest[trie[k][x^1]]>=limit)
return ask(trie[k][x^1],val,deep-1,limit);
else
return ask(trie[k][x],val,deep-1,limit);
}
用法
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++){
scanf("%d",&s[i]);
root[i]=++tot;
insert(root[i-1],root[i],s[i],i,31);
}
for(i=0;i<q;i++){
scanf("%d%d%d",&x,&l,&r);
l++;r++;
cout<<ask(root[r],x,31,l)<<"\n";
}
可持续化Trie树相对于主席树来说更方便,因为Trie树本身就是动态开点所以插入的时候直接在开一个新的头节点然后以这个头节点为基础扩展一条新边即可,和主席树不同的是可持续化Trie树没有利用前缀和,而是利用一个latest数组来存储此节点等到达的所有值中在原输入数组中的序号的最大值,这样就可以查询时利用root[r]所连接的所有节点都不会超过r的特性确定右边界,然后再利用按位贪心来求是否存在满足左边界条件而且符合异或的值,最后求得的是符合条件的原输入数组的序号。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=301000;
int trie[MAX_N*32][2],latest[MAX_N*32];
int s[MAX_N],root[MAX_N],tot;
void insert(int k,int k1,int val,int i,int deep){
if(deep<0){
latest[k1]=i;
return;
}
int x=(val>>deep)&1;
if(k)
trie[k1][x^1]=trie[k][x^1];
trie[k1][x]=++tot;
insert(trie[k][x],trie[k1][x],val,i,deep-1);
latest[k1]=max(latest[trie[k1][0]],latest[trie[k1][1]]);
}
int ask(int k,int val,int deep,int limit){
if(deep<0)
return s[latest[k]]^val;
int x=(val>>deep)&1;
if(latest[trie[k][x^1]]>=limit)
return ask(trie[k][x^1],val,deep-1,limit);
else
return ask(trie[k][x],val,deep-1,limit);
}
int main(void){
int n,q,x,i,l,r;
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++){
scanf("%d",&s[i]);
root[i]=++tot;
insert(root[i-1],root[i],s[i],i,31);
}
for(i=0;i<q;i++){
scanf("%d%d%d",&x,&l,&r);
l++;r++;
cout<<ask(root[r],x,31,l)<<"\n";
}
return 0;
}