256. 最大异或和

题目链接

256. 最大异或和

给定一个非负整数序列 \(a\) ,初始长度为 \(N\)
\(M\) 个操作,有以下两种操作类型:

  1. A x:添加操作,表示在序列末尾添加一个数 \(x\) ,序列的长度 \(N\) 增大 1 。
  2. Q l r x:询问操作,你需要找到一个位置 \(p\) ,满足 \(l \leq p \leq r\) ,使得: \(a[p]\) xor a \([p+1]\) xor \(\ldots\) xor \(a[N]\) xor \(x\) 最 大,输出这个最大值。

输入格式

第一行包含两个整数 \(N, M\) ,含义如问题描述所示。
第二行包含 \(N\) 个非负整数,表示初始的序列 \(A_{\text {。 }}\)
接下来 \(M\) 行,每行描述一个操作,格式如题面所述。
输出格式
每个询问操作输出一个整数,表示询问的答案。
每个答案占一行。

数据范围

\( N, M \leq 3 \times 10^{5}, 0 \leq a[i] \leq 10^{7} \text { 。 } \)

输入样例:

5 5
2 6 4 3 6
A 1 
Q 3 5 4 
A 4 
Q 5 7 0 
Q 3 6 6 

输出样例:

4
5
6

解题思路

可持久化 trie

可持久化 trie 关键在于维护所有版本的信息,每次插入一个数,每次创建一个根节点,并且将前面的信息复制过来,但不是完全复制,而是利用了本身的信息,如下:
image
即插入一个数时,要利用上一个版本的信息,一层一层的进行操作,如果上一个版本有信息,则将该层信息复制过来,再生成本层应该生成的信息,这样所有的信息都能维护到

本题即求 \(s_{p-1} \bigoplus s_n\) 的最大值,其中 \(s_i\) 为前缀异或值,\(l\leq p \leq r\),如果在 \(1\sim r\) 范围内,则可利用可持久化 trie 解决(\(root[r]\) 维护了前 \(r\) 个版本的信息),可以在每个节点上维护以该节点为子树的最大下标,当需要该节点时只需要判断该下标是否不小于 \(l\) 即可

  • 时间复杂度:\(O((m+n)\times logn)\)

代码

// Problem: 最大异或和
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/258/
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=6e5+5,M=N*24;
int n,m,s[N],tr[M][2],root[N],max_id[M],idx;
void insert(int i,int k,int p,int q)
{
	if(k<0)
	{
		max_id[q]=i;
		return ;
	}
	int v=s[i]>>k&1;
	if(p)tr[q][v^1]=tr[p][v^1];
	tr[q][v]=++idx;
	insert(i,k-1,tr[p][v],tr[q][v]);
	max_id[q]=max(max_id[tr[q][0]],max_id[tr[q][1]]);
}
int ask(int l,int root,int C)
{
	int p=root;
	for(int i=23;i>=0;i--)
	{
		int t=C>>i&1;
		if(max_id[tr[p][t^1]]>=l)p=tr[p][t^1];
		else
			p=tr[p][t];
	}
	return C^s[max_id[p]];
}
int main()
{
    scanf("%d%d",&n,&m);
    root[0]=++idx,max_id[0]=-1;
    insert(0,23,0,root[0]);
    for(int i=1;i<=n;i++)
    {
    	int x;
    	scanf("%d",&x);
    	s[i]=s[i-1]^x;
    	root[i]=++idx;
    	insert(i,23,root[i-1],root[i]);
    }
    char op[2];
    int l,r,x;
    while(m--)
    {
    	scanf("%s",op);
    	if(*op=='A')
    	{
    		scanf("%d",&x);
    		n++;
    		s[n]=s[n-1]^x;
    		root[n]=++idx;
    		insert(n,23,root[n-1],root[n]);
    	}
    	else
    	{
    		scanf("%d%d%d",&l,&r,&x);
    		printf("%d\n",ask(l-1,root[r-1],s[n]^x));	
    	}
    }
    return 0;
}
posted @ 2022-04-15 22:28  zyy2001  阅读(30)  评论(0编辑  收藏  举报