最大异或和(xor)
最大异或和(xor)
题目描述
给定一个非负整数序列{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 最大,输出最大是多少。
输入
第一行包含两个整数N,M,含义如问题描述所示。
第二行包含N个非负整数,表示初始的序列A。
接下来M行,每行描述一个操作,格式如题面所述。
输出
假设询问操作有T个,则输出应该有T行,每行一个整数表示询问的答案。
样例输入
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
提示
本题共有10个测试点,每个测试点10分。
对于测试点1-2,N,M<=5。
对于测试点3-7,N,M<=80000。
对于测试点8-10,N,M<=300000。
其中测试点1, 3, 5, 7, 9保证没有修改操作。
对于100%的数据,0<=a[i]<=10^7。
solution
考虑异或满足前缀相减。
答案=1~an~x的异或和异或1~i的异或和
前一部分是定值。
后一部分,我们对于每一个前缀都加进trie树,在trie上贪心即可。
建议写递归写法,注意边界。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 int n,m,rt[600005],now,cnt; 9 struct trie{ 10 int ch[2],v; 11 }tr[600005*26]; 12 void ins(int k,int la,int v){ 13 for(int i=25;i>=0;i--){ 14 tr[k].v=tr[la].v+1; 15 bool t=((v&(1<<i))>0); 16 tr[k].ch[!t]=tr[la].ch[!t]; 17 tr[k].ch[t]=++cnt; 18 k=tr[k].ch[t],la=tr[la].ch[t]; 19 } 20 tr[k].v=tr[la].v+1; 21 } 22 int ask(int k,int la,int v){ 23 int ans=0; 24 for(int i=25;i>=0;i--){ 25 bool t=((v&(1<<i))>0);t=(!t); 26 int s1=tr[k].ch[t],s2=tr[la].ch[t]; 27 if(tr[s1].v>tr[s2].v){ 28 ans+=(1<<i);k=s1;la=s2; 29 } 30 else{ 31 k=tr[k].ch[!t],la=tr[la].ch[!t]; 32 } 33 } 34 return ans; 35 } 36 int main() 37 { 38 cin>>n>>m; 39 for(int i=1,t;i<=n;i++){ 40 scanf("%d",&t); 41 rt[i]=++cnt; 42 now^=t;ins(rt[i],rt[i-1],now); 43 } 44 int rn=n; 45 for(int i=1,t,a,b;i<=m;i++){ 46 char c;scanf(" %c",&c); 47 if(c=='A'){ 48 scanf("%d",&t);rn++;rt[rn]=++cnt; 49 now^=t;ins(rt[rn],rt[rn-1],now); 50 } 51 else { 52 scanf("%d%d%d",&a,&b,&t);t^=now; 53 if(b==1)printf("%d\n",t); 54 else { 55 //cout<<rt[b-1]<<' '<<rt[a-2]<<endl; 56 printf("%d\n",ask(rt[b-1],a-2>0?rt[a-2]:0,t)); 57 } 58 } 59 } 60 return 0; 61 }