最大异或和

题目

展开
题目描述
给定一个非负整数序列 {a}{a},初始长度为nn。

有 mm 个操作,有以下两种操作类型:

A x:添加操作,表示在序列末尾添加一个数 xx,序列的长度 n+1n+1。
Q l r x:询问操作,你需要找到一个位置 pp,满足l \le p \le rl≤p≤r,使得: a[p] \oplus a[p+1] \oplus … \oplus a[N] \oplus xa[p]⊕a[p+1]⊕…⊕a[N]⊕x 最大,输出最大是多少。
输入格式
第一行包含两个整数 N,MN,M,含义如问题描述所示。
第二行包含 NN个非负整数,表示初始的序列AA 。
接下来 MM行,每行描述一个操作,格式如题面所述。

输出格式
假设询问操作有 TT 个,则输出应该有 TT 行,每行一个整数表示询问的答案。

输入输出样例
输入 #1复制
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
输出 #1复制
4
5
6
说明/提示
对于测试点 1-21−2,N,M \le 5N,M≤5。
对于测试点 3-73−7,N,M \le 80000N,M≤80000。
对于测试点 8-108−10,N,M \le 300000N,M≤300000。
其中测试点 1, 3, 5, 7, 91,3,5,7,9保证没有修改操作。
0 \le a[i] \le 10^70≤a[i]≤10
7

思路

首先操作离线下来,处理出添加完所有数后数列的状态,直接把所有后缀异或和插入进可持久化trie树里。然后倒着处理操作,这样添加就变成了删除。

删除结尾的一个数,剩下的所有后缀异或和都会异或上删掉的数。在全局维护一个tag,删一个数就把tag异或上它。在查询时只要tag这一位上为1就要反着走。

代码

#include<bits/stdc++.h>
#define Maxn 600010
#define Maxdep 23
char buf[1<<21],*p1=buf,*p2=buf;
int n,m;
int sum[Maxn];
struct trie
{
    trie *chd[2];
    int symbl;
    trie()
    {
        for(int i=0;i<2;i++) chd[i]=NULL;
        symbl=0;
    }
}*root[Maxn],tree[Maxn<<5],*tail;
void Init(){tail=tree;} 
void build(trie *&p,int dep)
{
    p=new (tail++)trie();
    if(dep<0) return ;
    build(p->chd[0],dep-1);
}
void update(trie *&p,trie *flag,int dep,int i)
{
    p=new (tail++)trie();
    if(flag) *p=*flag;
    if(dep<0) return (void)(p->symbl=i);
    int tmp=(sum[i]>>dep)&1;//判断是1还是0 
    if(!tmp) update(p->chd[0],flag?flag->chd[0]:NULL,dep-1,i);
    else update(p->chd[1],flag?flag->chd[1]:NULL,dep-1,i);
    if(p->chd[0]) p->symbl=std::max(p->symbl,p->chd[0]->symbl);
    if(p->chd[1]) p->symbl=std::max(p->symbl,p->chd[1]->symbl);
}
int query(trie *p,int x,int dep,int limit)
{
    if(dep<0) return sum[p->symbl]^x;
    int tmp=(x>>dep)&1;
    if(p->chd[tmp^1]&&p->chd[tmp^1]->symbl>=limit) return query(p->chd[tmp^1],x,dep-1,limit);
    return query(p->chd[tmp],x,dep-1,limit);
}
signed main()
{
    Init();
    read(n),read(m);
    build(root[0],Maxdep);
    for(int i=1,x;i<=n;i++)
    {
        read(x);
        sum[i]=sum[i-1]^x;
        update(root[i],root[i-1],Maxdep,i);
    } 
    for(int i=1;i<=m;i++)
    {
        char ch=getchar();
        while(ch!='A'&&ch!='Q') ch=getchar();
        if(ch=='A')
        {
            int x;
            read(x);
            n++;
            sum[n]=sum[n-1]^x;
            update(root[n],root[n-1],Maxdep,n);	
            continue;
        }	
        if(ch=='Q')
        {
            int l,r,x;
            read(l),read(r),read(x);
            int ans=query(root[r-1],sum[n]^x,Maxdep,l-1);
            printf("%d\n",ans);
            continue;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值