异或
给出 n 个数,Q次询问,每次问[l,r]中最大连续异或和。
为了体现在线操作,对于每次询问(x,y):
l=min( ((x+lastans) MOD n)+1 , ((y+lastans) MOD n)+1 )
r=max( ((x+lastans) MOD n)+1 , ((y+lastans) MOD n)+1 )
1.2 输入格式
第一行为两个整数n,m,分别表示数的个数和询问次数。
接下来一行 n 个数,再接下来 m 行,每行两个数 x,y,表示给出询问 (x,y) ,通过上述操作得到l和r,查询 [l,r] 中最大连续异或和。
1.3 输出格式
输出m行,每行一个整数表示该次询问的答案。
1.4 样例输入
3 3
1 4 3
0 1
0 1
4 3
1.5 样例输出
5
7
7
1.6 数据范围与约定
对于30%的数据,n <= 500, Q <= 500。
对于100%的数据,n <= 12000 , Q <= 6000 , 给出的数均在signed long int 范围内,且均为非负数。
强制在线,区间连续异或和,很明显的一道可持久化trie树。
30分做法
枚举l,r,做个前缀异或和,暴力统计就行了,复杂度O(n^3)
50分做法
考虑怎样就不用枚举r了,trie树,对吧!我们可以先把每个数加进trie里,然后从l到r贪心往下找就好。
复杂度O(n^2logn)
70分算法
考虑优化上一个算法。我们可以用可持久化trie树优化掉把元素加入trie的过程,好像也没好多少
100分正解
继续优化上一个算法。既然已经可以查询[l,r]内与x异或最大数,我们可以把所有答案全预处理出来。
O(n^2logn)警报
好吧,看来不能预处理这么多。那能不能先预处理一部分,再在询问中处理一部分?
这不就是分块的思想吗!!!
于是,我们可以预处理出每个块的左端点到它右边的所有区间的最大异或和。
设f[i][j]表示第i块的左端点,到j,也就是[(i-1)*len+1,j]的区间最大异或和。
转移方程就不用多说了。
于是,我们在查询一个[l,r]时,答案可以来自两部分:起始点在l-1所在的块内,或者块外。
对于块内的情况,贪心去查trie树即可。
对于块外,用我们预处理的f就行。
复杂度O(n^1.5log(maxlongint))