洛谷 P4735 最大异或和 解题报告

P4735 最大异或和

题目描述

给定一个非负整数序列\(\{a\}\),初始长度为\(N\)

\(M\)个操作,有以下两种操作类型:

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

输入输出格式

输入格式:

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

输出格式:

假设询问操作有 \(T\) 个,则输出应该有 \(T\) 行,每行一个整数表示询问的答案。

说明

对于测试点 \(1-2\)\(N,M \le 5\)
对于测试点 \(3-7\)\(N,M \le 80000\)
对于测试点 \(8-10\)\(N,M \le 300000\)
其中测试点 \(1, 3, 5, 7, 9\)保证没有修改操作。
\(0 \le a[i] \le 10^7\)


不知道为什么觉得这玩意儿挺可爱。

可持久化字典树,思想上和可持久化的所有东西都差不多,每次加入修改的一部分副本,剩下的用之前的。

大致流程是,和前一个点一起带进去,安排自己的儿子,然后把前一个点的儿子拿过来用。

对于这个题目,由异或的性质可以等价于求

\(s[p] \oplus s[n] \oplus x\)的最大值,其中\(s[i]\)表示异或前缀和,然后后面两个是一个可以得到的值,我们只需要在一个区间的数中找到一个数与它异或起来最大就可以了。

如果我们可以在那个区间的字典树上找相反的点,就可以得到最大值了。

于是把可持久化字典树建出来,查询\(r-1\)之前的字典树,为了不查到\(l-1\)之前的,对字典树每个节点维护一下这棵子树的编号最大的末尾节点。

注意细节,要先建一个0为根的树


Code:

#include <cstdio>
#include <cctype>
const int N=6e5+10;
int read()
{
    int x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
    return x;
}
int n,m,s[N],mx[N*24],ch[N*24][2],root[N],tot;char op[3];
int max(int x,int y){return x>y?x:y;}
#define ls ch[now][0]
#define rs ch[now][1]
void Insert(int las,int &now,int dep,int id)
{
    if(!now) now=++tot;
    if(!(~dep)) {mx[now]=id;return;}
    Insert(ch[las][s[id]>>dep&1],ch[now][s[id]>>dep&1],dep-1,id);
    if(!ls)ls=ch[las][0];if(!rs)rs=ch[las][1];
    mx[now]=max(mx[ls],mx[rs]);
}
int query(int now,int les,int x,int dep)
{
    if(!(~dep)) return x^s[mx[now]];
    int bit=x>>dep&1;
    if(mx[ch[now][bit^1]]>=les)
        return query(ch[now][bit^1],les,x,dep-1);
    else
        return query(ch[now][bit],les,x,dep-1);
}
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main()
{
    scanf("%d%d",&n,&m);
    mx[0]=-1;
    Insert(0,root[0],23,0);
    rep(i,1,n)
        s[i]=s[i-1]^read(),Insert(root[i-1],root[i],23,i);
    rep(i,1,m)
    {
        scanf("%s",op);
        if(op[0]=='A')
        {
            ++n,s[n]=s[n-1]^read();
            Insert(root[n-1],root[n],23,n);
        }
        else
        {
            int l=read(),r=read();
            printf("%d\n",query(root[r-1],l-1,s[n]^read(),23));
        }
    }
    return 0;
}

2018.11.2

posted @ 2018-11-02 11:46  露迭月  阅读(223)  评论(0编辑  收藏  举报