[Luogu P4735]最大异或和(可持久化Trie)

[Luogu P4735]最大异或和(可持久化Trie)

题面

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

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

1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。

2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。

分析

维护\(sum[i]=sum[i-1] \ \text{XOR} \ a[i]\),那么答案就是\(sum[p-1] \ \text{XOR} \ sum[n] \ \text{XOR} \ x\).这样\(a[1],a[2] \dots a[p-1]\)都被异或了两次抵消掉。

那么问题就变成,找到一个位置\(p\),满足\(l\leq p \leq r\),使得对于定值\(val=x \ \text{XOR} \ a[n]\),有\(val \ \text{XOR} \ a[p-1]\)最大。类似[51nod 1295]Xor key(可持久化trie)这样求解。

代码

#include<iostream>
#include<cstdio>
#define maxlog 32
#define maxn 600000
using namespace std;

struct persist_trie{
    int sz[maxn*maxlog+5];
    int root[maxn+5];
    int ch[maxn*maxlog+5][2];
    int ptr;
    void insert(int pos,int val){
        int now=root[pos]=++ptr;
        int last=root[pos-1];
        for(int i=maxlog-1;i>=0;i--){
            sz[now]=sz[last]+1;
            int k=(val>>i)&1;
            ch[now][k]=++ptr;
            ch[now][k^1]=ch[last][k^1];
            now=ch[now][k];
            last=ch[last][k];
        }
        sz[now]=sz[last]+1;
    }
    int query(int l,int r,int val){
        int now=root[r];
        int last=root[l-1];
        int ans=0;
        for(int i=maxlog-1;i>=0;i--){
            int k=(val>>i)&1;
            int lsz=sz[ch[now][k^1]]-sz[ch[last][k^1]];
            if(lsz){
                now=ch[now][k^1];
                last=ch[last][k^1];
                ans=ans<<1|1;
            }else{
                now=ch[now][k];
                last=ch[last][k];
                ans=ans<<1;
            }
        }
        return ans;
    }
}T;

int n,m;
int a[maxn+5],sum[maxn+5];
//sum[p]表示前缀异或和
//a[p]^a[p+1]^...a[n]=sum[p-1]^sum[n]
//问题变成已知x^sum[n],在[l,r]中求一个sum[i],使得sum[i]^(x^sum[n])最大
int main(){
    int l,r,x;
    char ch[10];
    scanf("%d %d",&n,&m);
    T.insert(0,sum[0]);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]^a[i];
        T.insert(i,sum[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%s",ch);
        if(ch[0]=='A'){
            scanf("%d",&x);
            n++;
            sum[n]=sum[n-1]^x;
            T.insert(n,sum[n]);
        }else{
            scanf("%d %d %d",&l,&r,&x);
            printf("%d\n",T.query(max(l-1,1),r-1,x^sum[n]));
        }
    }
}

原文地址:https://www.cnblogs.com/birchtree/p/12219610.html

时间: 2024-10-25 13:05:42

[Luogu P4735]最大异或和(可持久化Trie)的相关文章

BZOJ 3261: 最大异或和 [可持久化Trie]

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1513  Solved: 657[Submit][Status][Discuss] Description 给定一个非负整数序列 {a},初始长度为 N.       有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p]

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {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行,每行描述一个

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

【BZOJ4103】[Thu Summer Camp 2015]异或运算 可持久化Trie树

[BZOJ4103][Thu Summer Camp 2015]异或运算 Description 给定长度为n的数列X={x1,x2,...,xn}和长度为m的数列Y={y1,y2,...,ym},令矩阵A中第i行第j列的值Aij=xi xor  yj,每次询问给定矩形区域i∈[u,d],j∈[l,r],找出第k大的Aij. Input 第一行包含两个正整数n,m,分别表示两个数列的长度 第二行包含n个非负整数xi 第三行包含m个非负整数yj 第四行包含一个正整数p,表示询问次数 随后p行,每行

bzoj3261: 最大异或和 可持久化trie

题意:给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1. 2.Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 题解:可持久化trie 用前缀异或来建树,查询就变成了last^x和l到r中a[p]异或最大值是多少 先插入一个0,然后像可持久化线段树那样建树即可,还是挺简单的 /**

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

BZOJ 3261 最大异或和 可持久化Trie树

题目大意:给定一个序列,提供下列操作: 1.在数组结尾插入一个数 2.给定l,r,x,求一个l<=p<=r,使x^a[p]^a[p+1]^...^a[n]最大 首先我们可以维护前缀和 然后就是使x^sum[n]^sum[p-1]最大 x^sum[n]为定值,于是用Trie树贪心即可 考虑到l-1<=p-1<=r-1,我们不能对于每个询问都建一棵Trie树,但是我们可以对于Trie数维护前缀和,建立可持久化Trie树 每个区间[l,r]的Trie树为tree[r]-tree[l-1]

P4592 [TJOI2018]异或 (可持久化Trie)

[题目链接] https://www.luogu.org/problemnew/show/P4592 题目描述 现在有一颗以\(1\)为根节点的由\(n\)个节点组成的树,树上每个节点上都有一个权值\(v_i\).现在有\(Q\)次操作,操作如下: \(1\;x\;y:\)查询节点xx的子树中与\(y\)异或结果的最大值 \(2\;x\;y\;z:\)查询路径\(x\)到\(y\)上点与\(z\)异或结果最大值 打挂代码 题解代码 原文地址:https://www.cnblogs.com/liz

bzoj4103[Thu Summer Camp 2015]异或运算(可持久化trie树)

一看数据范围,n很小m很大,对长的那一维建可持久化线段树,另一维暴力枚举 1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int n,m,cnt,tot,p; 7 int rt[300005]; 8 int x[2005]; 9 int y[300005]; 10 struct Trie{ 11 in