预处理 数组的前缀和,问题就变成在[l - 1,r] 区间内找任意两个数,使得异或值尽可能大。
用可持久化 trie 暴力做 复杂度是
即使去掉 32 这个系数,也可能会被卡常,考虑如何优化。
考虑预处理一部分区间的答案,令 表示 区间 的答案,显然不能预处理全部的区间,考虑分块预处理:对 l 分块(或者对 r 分块),f[l][r] 表示 从第 l 个 块的起点到 r 这段区间内 与 a[r] 异或的最大值。g[l][r] 表示 从第 l 个 块的起点到 r 这段区间内的答案。
通过 f[l][r] 和 g[l][r - 1] 可以得到 g[l][r],因此可以边搞边处理。
对于每一次询问[l,r],找到 l 所在块号的右边界 ,对于 [ed + 1,r] 的答案已经预处理过,枚举 [l,ed] 每一个点,在可持久化 trie 上查询 区间 [l + 1,r] 与 a[l] 异或可得到的最大值,[ed + 1,r]的答案合并即得到[l,r] 的答案。
复杂度:
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4 + 10;
typedef long long ll;
int n,m;
ll a[maxn],f[150][maxn];
struct trie{ //可持久化字典树
int sz,son[maxn * 40][2],sum[maxn * 40],root[maxn];
void init() {
for(int i = 0; i <= sz; i++)
son[i][0] = son[i][1] = sum[i] = root[i] = 0;
sz = 0;
}
void upd(int &rt,ll v) { //类似主席树的更新,每一步都要更新一个结点
++sz;
son[sz][0] = son[rt][0];
son[sz][1] = son[rt][1];
sum[sz] = sum[rt] + 1;
rt = sz;
int t = rt;
for(int i = 32; i >= 0; i--) {
int p = (v >> i) & 1;
++sz;
int s = son[t][p];
sum[sz] = sum[s] + 1;
son[sz][0] = son[s][0];
son[sz][1] = son[s][1];
son[t][p] = sz;
t = son[t][p];
}
}
ll qry(int l,int r,ll v) {
ll ans = 0;
int L = root[max(l - 1,0)],R = root[r];
for(int i = 32; i >= 0; i--) {
int p = (v >> i) & 1;
if(sum[son[R][p ^ 1]] - sum[son[L][p ^ 1]] > 0) {
L = son[L][p ^ 1],R = son[R][p ^ 1];
ans |= (1ll << i);
} else {
L = son[L][p],R = son[R][p];
}
}
return ans;
}
}trie;
int main() {
scanf("%d%d",&n,&m);
trie.init();
a[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld",&a[i]);
a[i] ^= a[i - 1];
trie.root[i] = trie.root[i - 1];
trie.upd(trie.root[i],a[i]);
}
int block = min(n,120);
for (int j = 1; (j - 1) * block + 1 <= n; j++) { //枚举块的起点
for (int i = (j - 1) * block + 1; i <= n; i++) { //枚举终点
f[j][i] = trie.qry((j - 1) * block + 1,i,a[i]);
f[j][i] = max(f[j][i - 1],f[j][i]);
}
}
ll lstans = 0;
for (ll i = 1,x,y,l,r,nl,p; i <= m; i++) {
scanf("%lld%lld",&x,&y);
l = min((x + lstans) % n + 1,(1ll * y + lstans) % n + 1) - 1;
r = max((x + lstans) % n + 1,(1ll * y + lstans) % n + 1);
p = l / block + 1 + (l % block > 0);
nl = (p - 1) * block;
lstans = 0;
if (nl > r) {
for (int k = l; k <= r; k++)
lstans = max(lstans,trie.qry(k,r,a[k]));
} else {
lstans = f[p][r];
for (int k = l; k <= nl; k++)
lstans = max(lstans,trie.qry(l,r,a[k]));
}
printf("%lld\n",lstans);
}
return 0;
}
来源:CSDN
作者:猝死在学ACM的路上
链接:https://blog.csdn.net/qq_41997978/article/details/103927985