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

题目链接

题解

看到异或和最大就应该想到01 trie树

我们记\(S_i\)为前i项的异或和

那么我们的目的是最大化\(S_n\)^\(x\)^\(S_{j-1}\) \((l <= j <= r)\) (注意是\(j-1\), 所以l和r都要减1)
\(S_n\)^\(x\)已经固定, 那么我们可以把\(S_j\)放入trie树搞

那么怎么处理区间呢?
类似主席树
记录一下\([1-i]\)每个节点被多少个数经过

那么两棵trie树相减,就得到了 \([l-r]\)这段区间的信息

然后就是经典的模型了

Code

#include<bits/stdc++.h>
const int N = 600010, M = 25;
#define LL long long
#define RG register

int ch[N*30][2], sum[N*30], root[N], cnt, tot, ans;

using namespace std;

inline int gi() {
    RG int x = 0; RG char c = getchar(); bool f = 0;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') c = getchar(), f = 1;
    while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
    return f ? -x : x;
}

void insert(int &now, int x, int dep) {
    sum[++cnt] = sum[now]+1;
    ch[cnt][0] = ch[now][0]; ch[cnt][1] = ch[now][1];
    now = cnt;
    if (dep < 0) return ;
    insert(ch[now][(x >> dep) & 1], x, dep-1);
    return ;
}

void query(int rt1, int rt2, int x, int dep) {
    if (dep < 0) return ;
    int k = (x >> dep)&1;
    if (sum[ch[rt2][k^1]]-sum[ch[rt1][k^1]] > 0) {
        ans |= (1 << dep);
        query(ch[rt1][k^1], ch[rt2][k^1], x, dep-1);
    }
    else query(ch[rt1][k], ch[rt2][k], x, dep-1);
    return ;
}

int main() {
    //freopen(".in", "r", stdin);
    //freopen(".out", "w", stdout);
    int n = gi(), m = gi();
    for (int i = 1; i <= n; i++) {
        int x = gi();
        tot ^= x; root[i] = root[i-1];
        insert(root[i], tot, M-1);
    }
    for (int i = 1; i <= m; i++) {
        char c = getchar();
        while (c != 'A' && c != 'Q') c = getchar();
        if (c == 'A') {
            int x = gi();
            tot ^= x;
            root[n+1] = root[n];
            insert(root[++n], tot, M-1);
        }
        else {
            int l = gi()-1, r = gi()-1, x = gi();
            ans = 0;
            query(root[l-1], root[r], tot^x, M-1);
            if (!l) ans = max(ans, tot^x);
            printf("%d\n", ans);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zzy2005/p/10138650.html

时间: 2024-10-01 06:39:09

bzoj3261: 最大异或和 (可持久化trie树)的相关文章

[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

【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行,每行描述一个

【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行,每行

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]

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[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

[BZOJ3261&amp;BZOJ3166]可持久化trie树及其应用

可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系即可. tr[y].son[p xor 1]:=tr[x].son[p xor 1]; tr[y].sum:=tr[x].sum+1; 这两句要好好体会,对之后理解query过程中的语句很有帮助. if (tr[tr[x].son[p xor 1]].sum=tr[tr[x].son[p xor 1

【BZOJ3689】异或之 堆+可持久化Trie树

[BZOJ3689]异或之 Description 给定n个非负整数A[1], A[2], ……, A[n].对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数.求这些数(不包含A[i])中前k小的数.注:xor对应于pascal中的“xor”,C++中的“^”. Input 第一行2个正整数 n,k,如题所述.以下n行,每行一个非负整数表示A[i]. Output 共一行k个数,表示前k小的数. Samp

bzoj 3261: 最大异或和 (可持久化trie树)

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Description 给定一个非负整数序列 {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 最大,输出最大是多少. Inp