bzoj 3261 最大异或和 可持久化字典树(01树)
思路:
由异或的性质可得,题目要求的式子可以转化成求$max(pre[n]^x^pre[i])$,$pre[i]$表示前缀异或和,那么我们现在就要求出这个东西,所以用可持久化字典树来求,每次贪心的往相反的方向看是否有值,具体看代码即可,模板题,注意最好先插入一个0,查询区间的$(l,r)$也要注意一下端点,记住我们要的是前缀。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) typedef long long ll; using namespace std; const int maxn=600010; int sum[maxn*30],tr[maxn*30][2],cnt,root[maxn]; int pre,n,m,l,r,d[30]; void split(int x) { int len=0; while(x>0){ d[len++]=x%2; x/=2; } while(len<27)d[len++]=0; } inline void update(int &rt,int las){ sum[rt=++cnt]=sum[las]+1; int tmp=rt; for(int i=27;i>=0;i--){ tr[tmp][d[i]^1]=tr[las][d[i]^1]; tr[tmp][d[i]]=++cnt,las=tr[las][d[i]]; sum[tmp=cnt]=sum[las]+1; } } int query(int l,int r){ int ans=0; for(int i=27;i>=0;i--) { if(sum[tr[r][d[i]^1]]-sum[tr[l][d[i]^1]]>0){ ans|=(1<<i); r=tr[r][d[i]^1],l=tr[l][d[i]^1]; }else{ r=tr[r][d[i]],l=tr[l][d[i]]; } } return ans; } int main(){ while(cin>>n>>m) { pre=0; split(0); update(root[1],root[0]); n++; for(int i=2;i<=n;i++) { int x; scanf("%d",&x); pre^=x; split(pre); update(root[i],root[i-1]); } char op[10]; for(int i=1;i<=m;i++) { scanf("%s",op); if(op[0]=='A'){ n++; int x; scanf("%d",&x); pre^=x; split(pre); update(root[n],root[n-1]); }else{ int l,r,x; scanf("%d%d%d",&l,&r,&x); split(pre^x); printf("%d\n",query(root[l-1],root[r])); } } } }
——愿为泰山而不骄
qq850874665~~