可持久化01trie树——模板
给你一个数,在一段区间内找到另一个数,使得他们的异或最大;
trie树上存储每个数的二进制位,查询时贪心查询能让当前高位取得1的位置;
实际上是一个求前缀和的思想。每个数都开一个trie树浪费空间,当前建树的时候基本是转移前面的树;
首先设当前二进制位为d,将前一棵树的d^1直接转移(因为以后也用不到这一半),然后再递归转移d
最后更新当前树的当前位置的树的大小。(方便以后查询);
查询时,设给出的数当前位为d,我们要找到一个d^1的数才可以使得数更大,如果siz[r]-siz[l]>0说明存在这样的数,否则不存在;
字典树空间要开maxn*(最大二进制位数)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=2e5+10; int n,q; int trie[maxn*32][2]; int root[maxn]; int cnt; int siz[maxn*32]; void pushup(int nw) { siz[nw]=siz[trie[nw][0]]+siz[trie[nw][1]]; } void insert(int pre,int &nw,int i,int x) { nw=++cnt; siz[nw]=siz[pre]; if(i<0) { siz[nw]++; return ; } int d=(x>>i)&1; trie[nw][d^1]=trie[pre][d^1]; insert(trie[pre][d],trie[nw][d],i-1,x); pushup(nw); } int query(int l,int r,int i,int x) { if(i<0) return 0; int d=(x>>i)&1; int t=siz[trie[r][d^1]]-siz[trie[l][d^1]]; if(t>0) return query(trie[l][d^1],trie[r][d^1],i-1,x)+(1<<i); else return query(trie[l][d],trie[r][d],i-1,x); } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); insert(root[i-1],root[i],30,x); } for(int i=1;i<=q;i++) { int l,r,x; scanf("%d%d%d",&x,&l,&r); l++;r++; printf("%d\n",query(root[l-1],root[r],30,x)); } return 0; } /* */