Description
給定一個非負整數序列\(\{a\}\),初始長度爲\(N\)。ios
有\(M\)個操做,有如下兩種操做類型:git
A x
:添加操做,表示在序列末尾添加一個數\(x\),序列的長度\(N+1\)。Q l r x
:詢問操做,你須要找到一個位置\(p\),知足\(l \leq p \leq r\),使得: \(a[p] \oplus a[p+1] \oplus ... \oplus a[N] \oplus x\) 最大,輸出最大是多少。Input
第一行包含兩個整數 \(N,M\),含義如問題描述所示。數組
第二行包含 \(N\)個非負整數,表示初始的序列\(A\) 。spa
接下來 \(M\)行,每行描述一個操做,格式如題面所述。code
Output
假設詢問操做有 \(T\) 個,則輸出應該有 \(T\) 行,每行一個整數表示詢問的答案。ip
表示是個裸的可持久化\(01Trie\)樹.get
考慮到\(\oplus\)具備的性質\((x\ \oplus \ y) \oplus y=x\)input
因此咱們最終所求就是$sum[p-1]\oplus sum[n] \oplus x $it
(其中\(sum\)數組存儲異或前綴和.)io
想要求出最大值.咱們顯然已知\(sum[n] \oplus x\)
則要在\([l,r]\)中找出與\(sum[n]\oplus x\)異或起來的最大值。
顯然直接查詢便可.
代碼
#include<cstdio> #include<iostream> #include<algorithm> #define R register using namespace std; const int maxn=600009; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } struct Trie { int ch[maxn*35][2],cnt[maxn*35],tot,root[maxn]; Trie(){root[0]=tot=1;} inline void insert(R int lastroot,R int &nowroot,int x) { nowroot=++tot; int u=nowroot; for(R int i=30;~i;i--) { R int bit=(x>>i)&1; ch[u][!bit]=ch[lastroot][!bit]; ch[u][bit]=++tot; u=ch[u][bit]; lastroot=ch[lastroot][bit]; cnt[u]=cnt[lastroot]+1; } } inline int query(R int l,R int r,R int x) { R int res=0; for(R int i=30;~i;i--) { R int bit=(x>>i)&1; if(cnt[ch[r][!bit]]-cnt[ch[l][!bit]]) { l=ch[l][!bit]; r=ch[r][!bit]; res+=(1<<i); } else { l=ch[l][bit]; r=ch[r][bit]; } } return res; } }se; int n,m,sum[maxn],a[maxn]; char opt[5]; int main() { in(n),in(m);n++; for(R int i=2,x;i<=n;i++)in(a[i]); for(R int i=1;i<=n;i++)sum[i]=sum[i-1]^a[i]; for(R int i=1;i<=n;i++) se.insert(se.root[i-1],se.root[i],sum[i]); for(R int x,y,z;m;m--) { scanf("%s",opt+1); if(opt[1]=='A') { in(x);n++; sum[n]=sum[n-1]^x; se.insert(se.root[n-1],se.root[n],sum[n]); } else { in(x),in(y),in(z); printf("%d\n",se.query(se.root[x-1],se.root[y],sum[n]^z)); } } }