题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1295
第1行:2个数N, Q中间用空格分隔,分别表示数组的长度及查询的数量(1 <= N <= 50000, 1 <= Q <= 50000)。 第2 - N+1行:每行1个数,对应数组A的元素(0 <= A[i] <= 10^9)。 第N+2 - N+Q+1行:每行3个数X, L, R,中间用空格分隔。(0 <= X <= 10^9,0 <= L <= R < N)
输出共Q行,对应数组A的区间[L,R]中的数与X进行异或运算,所能得到的最大值。
15 8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 10 5 9 1023 6 6 33 4 7 182 4 9 181 0 12 5 9 14 99 7 8 33 9 13
13 1016 41 191 191 15 107 47
题解:
1.此题(HDU4825 Xor Sum)的加强版
2.由于要求的是x与区间[l,r]的某个数异或值最大,所以在Trie树的基础上,可以模仿可持久化线段树,建立一棵可持久化Trie树。这样就可以得到每插入一个数时的历史版本的Trie树。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 1e5+10; 18 19 struct Trie 20 { 21 int end[303*MAXN], next[33*MAXN][2]; 22 int root[MAXN], L = 0; 23 int newnode() 24 { 25 next[L][0] = next[L][1] = -1; 26 end[L++] = 0; 27 return L-1; 28 } 29 void init() 30 { 31 L = 0; 32 } 33 void build(LL val) //初始化版本 34 { 35 int tmp = root[0]; 36 for(int i = 32; i>=0; i--) 37 { 38 int way = (val>>i)&1; 39 if(next[tmp][way]==-1) next[tmp][way] = newnode(); 40 tmp = next[tmp][way]; 41 } 42 } 43 int insert(int preroot, LL val) 44 { 45 int newroot = newnode(), rootbuf = newroot; 46 for(int i = 32; i>=0; i--) 47 { 48 int way = (val>>i)&1; 49 next[newroot][way] = newnode(); //要走的路,新开出来 50 next[newroot][!way] = next[preroot][!way]; //另一条路,指向上一个历史版本的 51 52 newroot = next[newroot][way]; 53 preroot = next[preroot][way]; 54 end[newroot] = end[preroot]+1; //叠加 55 } 56 return rootbuf; 57 } 58 LL query(int Lroot, int Rroot, LL val) 59 { 60 LL ret = 0; 61 for(int i = 32; i>=0; i--) 62 { 63 ret <<= 1; 64 int way = (val>>i)&1; 65 if(next[Lroot][!way]!=-1 && (end[next[Rroot][!way]]-end[next[Lroot][!way]]>0)) 66 { 67 ret ^= 1; 68 Lroot = next[Lroot][!way]; 69 Rroot = next[Rroot][!way]; 70 } 71 else 72 { 73 Lroot = next[Lroot][way]; 74 Rroot = next[Rroot][way]; 75 } 76 } 77 return ret; 78 } 79 }; 80 Trie T; 81 82 LL a[MAXN]; 83 int main() 84 { 85 int n, q; 86 while(scanf("%d%d",&n,&q)!=EOF) 87 { 88 T.init(); 89 T.root[0] = T.newnode(); 90 for(int i = 1; i<=n; i++) //建立初始化版本 91 { 92 scanf("%lld",&a[i]); 93 T.build(a[i]); 94 } 95 for(int i = 1; i<=n; i++) //每插入一个数,就生成一个历史版本的Trie树 96 T.root[i] = T.insert(T.root[i-1],a[i]); 97 98 while(q--) 99 { 100 int x, l, r; 101 scanf("%d%d%d",&x,&l,&r); 102 l++; r++; 103 printf("%lld\n", T.query(T.root[l-1],T.root[r],1LL*x)); 104 } 105 } 106 }