1. 程式人生 > >BZOJ3261:最大異或和——題解

BZOJ3261:最大異或和——題解

cstring std IT digi problem ios names delta font

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

給定一個非負整數序列{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 最大,輸出最大是多少。

前置技能:HDU4825

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

參考:https://www.cnblogs.com/y7070/p/5000471.html

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

所以我們處理出所有前綴異或和完後往trie上插。

不過由於是區間詢問,所以按照主席樹(可持久化線段樹)的想法,我們建立可持久化trie,具體的建立方法大致和主席樹差不多,就不多講了直接看代碼吧。

(先割在這裏,去吃飯了。)

#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/+

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

BZOJ3261:最大異或和——題解