题目链接
题目大意
给定一个非负整数序列 (a),初始长度为 (N)。
有 (M) 个操作,有以下两种操作类型:
1、”(A) (X)”:添加操作,表示在序列末尾添加一个数 (X),序列的长度 (N) 增大 (1)。
2、”(Q) (l) (r) (X)”:询问操作,你需要找到一个位置 (p),满足 $ l≤p≤r(,使得:)a_p$ xor (a_{p+1}) xor (…) xor (a_N) xor (x) 最大,输出这个最大值。
解题思路
记录 (sum_i) 为前 (i) 个数的前缀和,那么 (a_p) xor (a_{p+1}) xor (…) xor (a_N) xor (X) = (sum_{p-1}) xor (sum_N) xor (X)
其中 (sum_N) xor (X) 是固定的,那么题目就可以转换为在区间 ([l , r]) 中找到一个 (p) 使得 (sum_{p- 1}) xor ((sum_N) xor (X)) 最大
即在区间 ([l-1,r-1]) 找到一个 (p) 使得 (sum_{p}) xor ((sum_N) xor (X)) 最大
然后就是跑可持久化01trie了
注意特判点 → 当 (r = 1) 时,(r - 1) 为 (0) ,(root[r- 1] = root[0] = 0) ,故 (root[r - 1]) 的指针无法在字典树上跳动,所以需要特判一下
AC_Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n , m , tot;
int a[N] , sum[N] , cnt[N * 31] , root[N] , tree[N * 31][2];
void insert(int id , int s)
{
root[id] = ++ tot;
int p = root[id] , q = root[id - 1];
for(int i = 31 ; ~i ; i --)
{
int x = s >> i & 1;
tree[p][x] = ++ tot;
tree[p][x ^ 1] = tree[q][x ^ 1];
p = tree[p][x] , q = tree[q][x];
cnt[p] = cnt[q] + 1;
}
}
int query(int l , int r , int s)
{
int res = 0 , p = root[r] , q = root[l - 1];
for(int i = 31 ; ~i ; i --)
{
int x = s >> i & 1;
if(cnt[tree[p][x ^ 1]] > cnt[tree[q][x ^ 1]])
{
res += 1LL << i;
p = tree[p][x ^ 1] , q = tree[q][x ^ 1];
}
else p = tree[p][x] , q = tree[q][x];
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
cin >> n >> m ;
for(int i = 1 ; i <= n ; i ++) cin >> a[i] , sum[i] = sum[i - 1] ^ a[i] , insert(i , sum[i]);
while(m --)
{
char op;
cin >> op;
if(op == 'A')
{
cin >> a[++ n];
sum[n] = sum[n - 1] ^ a[n];
insert(n , sum[n]);
}
else
{
int l , r , x;
cin >> l >> r >> x;
if(r == 1)
{
cout << (sum[n] ^ x) << '
';
continue ;
}
cout << query(l - 1 , r - 1 , sum[n] ^ x) << '
';
}
}
return 0;
}