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;
}
posted @ 2020-09-26 17:26  GsjzTle  阅读(176)  评论(0编辑  收藏  举报