P4735 最大异或和

链接:https://www.luogu.org/problemnew/show/P4735

题目描述

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

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

  1. A x:添加操作,表示在序列末尾添加一个数 xx ,序列的长度 N+1N+1 。
  2. Q l r x:询问操作,你需要找到一个位置 pp ,满足 l \le p \le rlpr ,使得: 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-212 , N,M \le 5N,M5 。
对于测试点 3-737 , N,M \le 80000N,M80000 。
对于测试点 8-10810 , N,M \le 300000N,M300000 。
其中测试点 1, 3, 5, 7, 91,3,5,7,9 保证没有修改操作。
0 \le a[i] \le 10^70a[i]107 。

题解:

先看简单版:

给出 n 个数,问最大连续异或和。(n<=100000 , num<=2^31-1)
经典贪心。再利用上异或的性质,即 b ^ a ^ b =a 。记录前缀异或和,即转化为找两个数使得其异或和最大,同前。O(n*位数)
 
我们先来考虑,若没有添加操作,显然可以将所有的后缀异或和建成可持久化Trie树来做。那如果添加了k个元素呢?
查询时可以将x异或上添加的k个元素,再到Trie中查询。
建树 O(N * 位数) ;单次查询 O(k + 位数)
注意边界,开始应该把数组整体右移,不然查询1的时候会出问题 

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int M = 600000 + 5, M_trie = M * 30;
int root[M], a[M], bin[33], tot;

struct Trie{
    
    struct node{
        int cnt[2];
        int ptr[2];
    }tree[M_trie];
    
    
    int insert(int num, int f){
        int res = ++tot; 
        int x = num, cur = res;
        tree[res] = tree[f];
        
        for(int i = 27; i; i--){
            int t = x & bin[i - 1]; t >>= (i - 1);
            int nw = ++tot;
            tree[cur].cnt[t]++;
            tree[cur].ptr[t] = nw;
            f = tree[f].ptr[t];
            tree[nw] = tree[f];
            cur = tree[cur].ptr[t];
            
        }
        return res;
    }
    
    int query(int lf, int rg, int num){
        int ans = 0;
        
        for(int i = 27; i; i--){
            int t = num & bin[i - 1]; t >>= (i - 1);
            if(tree[rg].cnt[t^1] - tree[lf].cnt[t^1]){
                lf = tree[lf].ptr[t^1], rg = tree[rg].ptr[t^1];
                ans += bin[i - 1];
            }
            else {
                lf = tree[lf].ptr[t], rg = tree[rg].ptr[t];
            }    
            
        }
        
        return ans;
        
    }
    
    
}Tr;

int query(int lf, int rg, int num){
    return Tr.query(root[lf - 1], root[rg], num);
}

int main(){
//    freopen("data.in","r",stdin);
//    freopen("mydata.out","w",stdout);
    bin[0] = 1;
    for(int i = 1; i <= 30; i++)bin[i] = bin[i - 1] << 1;
    
    int n, q;
    scanf("%d%d", &n, &q);
    ++n;
    root[1] = Tr.insert(0, root[0]);
    for(int i = 2; i <= n; i++){
        scanf("%d", &a[i]);
        a[i] ^= a[i - 1];
        root[i] = Tr.insert(a[i], root[i - 1]);    
    }
    int cnt = n; 
    char s[5];
    int x, l, r;
    for(int i = 1; i <= q; i++){    
        scanf("%s", s);
        if(s[0] == 'Q'){
            scanf("%d%d%d", &l, &r, &x);
            int num = a[cnt] ^ x;
        //    printf("QUERY:%d %d %d\n", a[l-1], a[r], num);
            printf("%d\n", query(l, r, num));
            
        }
        else {
            scanf("%d", &x);
            a[++cnt] = a[cnt - 1]^x;
            root[cnt] = Tr.insert(a[cnt], root[cnt - 1]);
    //        printf("ADD:%d\n", a[cnt]);
        }
        
        
    }
}
View Code

 

posted @ 2018-07-31 15:26  Ed_Sheeran  阅读(233)  评论(0编辑  收藏  举报