模板
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;
}