P4735 最大异或和
题目链接
题目大意
给定一个非负整数序列 \(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) << '\n';
continue ;
}
cout << query(l - 1 , r - 1 , sum[n] ^ x) << '\n';
}
}
return 0;
}
凡所不能将我击倒的,都将使我更加强大