256. 最大异或和

题目链接

256. 最大异或和

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

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

输入格式

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

数据范围

N,M3×105,0a[i]107 。 

输入样例:

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
即插入一个数时,要利用上一个版本的信息,一层一层的进行操作,如果上一个版本有信息,则将该层信息复制过来,再生成本层应该生成的信息,这样所有的信息都能维护到

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

  • 时间复杂度:O((m+n)×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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16151303.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示