BZOJ3261:最大異或和——題解

http://www.lydsy.com/JudgeOnline/problem.php?id=3261php

給定一個非負整數序列{a},初始長度爲N。
有M個操做,有如下兩種操做類型:
一、A x:添加操做,表示在序列末尾添加一個數x,序列的長度N+1。
二、Q l r x:詢問操做,你須要找到一個位置p,知足l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,輸出最大是多少。

前置技能:HDU4825html

會了這個前置技能以後默認你會如何建trie跑貪心了。node

參考:http://www.javashuo.com/article/p-xsulolpw-mq.htmlios

對於一段區間的異或和=r的前綴異或和^l-1的前綴異或和。git

因此咱們處理出全部前綴異或和完後往trie上插。spa

不過因爲是區間詢問,因此按照主席樹(可持久化線段樹)的想法,咱們創建可持久化trie,具體的創建方法大體和主席樹差很少,就很少講了直接看代碼吧。code

至於詢問,咱們直接詢問哪一個前綴能和(n的前綴異或和^x)異或值最大便可。htm

直接引用參考博客:blog

若是 x (詢問數)的這一位爲 p ,那麼咱們查詢Sum[son[l][p ^ 1]] - Sum[son[r][p ^ 1],Sum爲節點上有多少的值。get

如若 表達式 > 0 那麼咱們就像 p ^ 1 的方向行走,同時 答案加上 1 << d 由於這一位被咱們錯開了。

不然只好向 p 的方向行走, 不加上 1 << d。

緣由請參考前置技能。

另外還要注意咱們查詢的內容自己就是前綴和,左端點和右端點就須要同時減一,同時查區間,那麼左端點就還須要須要減一

參考裏提到了一個小技巧就是在最開始插一個0,這樣就不須要左端點和右端點同時減一了,否則本身看着怪難受的。

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int N=6e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
inline char getc(){
    char ch=getchar();
    while(ch!='A'&&ch!='Q')ch=getchar();
    return ch;
}
struct node{
    int son[2],sum;
}tr[50*N];
int tot,b[N],rt[N],pool;
void insert(int y,int &x,int k,int now){
    tr[x=++pool]=tr[y];
    tr[x].sum++;
    if(now<0)return;
    bool p=k&(1<<now);
    insert(tr[y].son[p],tr[x].son[p],k,now-1);
    return;
}
int query(int nl,int nr,int k,int now){
    if(now<0)return 0;
    bool p=k&(1<<now);
    int delta=tr[tr[nr].son[p^1]].sum-tr[tr[nl].son[p^1]].sum;
    if(delta>0)return (1<<now)+query(tr[nl].son[p^1],tr[nr].son[p^1],k,now-1);
    else return query(tr[nl].son[p],tr[nr].son[p],k,now-1);
}
int main(){
    int n=read()+1,m=read();
    for(int i=2;i<=n;i++)b[i]=b[i-1]^read();
    for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],b[i],24);
    for(int i=1;i<=m;i++){
    char ch=getc();
    if(ch=='A'){
        b[++n]=b[n-1]^read();
        insert(rt[n-1],rt[n],b[n],24);
    }else{
        int l=read(),r=read(),x=read();
        printf("%d\n",query(rt[l-1],rt[r],b[n]^x,24));
    }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文做者:luyouqi233。               +

 +歡迎訪問個人博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

相關文章
相關標籤/搜索