bzoj2741 FOTILE模拟赛L 可持久化Trie
2016-02-27 14:52
260 查看
首先将作前缀和sum[i]=a[1]^a[2]^...^a[i],将询问变为max{sum[x-1]^sum[y]},l<=x<=y<=r。
假设我们要得到max{sum[x]^sum[y]},l<=y<=r的值,我们可以构建一颗Trie,存储sum[l],sum[l+1],...sum[r]的二进制串,然后再Trie上面贪心找最大值(能走不同就走不同,可以见USACO TRAING的Xor一题)。
显然不可能存储n^2个Trie,然后我们可以用和主席树一样的方法构建可持久化Trie。实际上,构建得到的可持久化Trie和sum[]数组的主席树是一模一样的!只是查询的时候有点不同而已。
但是对于本题的询问,x是可以变化的。我们可以分块,然后用f[i][j]表示x>=第x块的头,y<=j时的max{sum[x-1]^sum[y]}(在代码中稍有不同)。那么对于查询(l,r),设l属于块u,那么首先得到ans=f[u+1][r],然后枚举块u中的可行节点更新答案即可。
时间复杂度O((M+N)N^0.5logN)。
AC代码如下:
by lych
2016.2.27
假设我们要得到max{sum[x]^sum[y]},l<=y<=r的值,我们可以构建一颗Trie,存储sum[l],sum[l+1],...sum[r]的二进制串,然后再Trie上面贪心找最大值(能走不同就走不同,可以见USACO TRAING的Xor一题)。
显然不可能存储n^2个Trie,然后我们可以用和主席树一样的方法构建可持久化Trie。实际上,构建得到的可持久化Trie和sum[]数组的主席树是一模一样的!只是查询的时候有点不同而已。
但是对于本题的询问,x是可以变化的。我们可以分块,然后用f[i][j]表示x>=第x块的头,y<=j时的max{sum[x-1]^sum[y]}(在代码中稍有不同)。那么对于查询(l,r),设l属于块u,那么首先得到ans=f[u+1][r],然后枚举块u中的可行节点更新答案即可。
时间复杂度O((M+N)N^0.5logN)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define N 13005 #define ll long long using namespace std; int n,m,trtot,ls[N<<5],rs[N<<5],sum[N<<5],rt ; int l ,r ,blg ,f[115] ,a ,bin[35]; void ins(int x,int &y,int k,int v){ y=++trtot; sum[y]=sum[x]+1; if (k<0) return; if (bin[k]&v){ ls[y]=ls[x]; ins(rs[x],rs[y],k-1,v); } else{ rs[y]=rs[x]; ins(ls[x],ls[y],k-1,v); } } int qry(int x,int y,int z){ x=rt[x-1]; y=rt[y]; int k=30,ans=0; for (; k>=0; k--){ int tmp=z&bin[k]; if (tmp) if (sum[ls[y]]-sum[ls[x]]){ x=ls[x]; y=ls[y]; ans|=bin[k]; } else{ x=rs[x]; y=rs[y]; } else if (sum[rs[y]]-sum[rs[x]]){ x=rs[x]; y=rs[y]; ans|=bin[k]; } else{ x=ls[x]; y=ls[y]; } } return ans; } int main(){ scanf("%d%d",&n,&m); int i,j; bin[0]=1; for (i=1; i<=30; i++) bin[i]=bin[i-1]<<1; a[1]=0; ins(rt[0],rt[1],30,0); n++; for (i=2; i<=n; i++){ scanf("%d",&a[i]); a[i]^=a[i-1]; ins(rt[i-1],rt[i],30,a[i]); } int cnt=(int)sqrt((double)n); for (i=1; i<=cnt; i++){ l[i]=r[i-1]+1; r[i]=r[i-1]+cnt; } r[cnt]=n; for (i=1; i<=cnt; i++){ for (j=l[i]; j<=r[i]; j++) blg[j]=i; for (j=l[i]; j<=n; j++) f[i][j]=max(f[i][j-1],qry(l[i],j,a[j])); } int ans=0,x,y; for (i=1; i<=m; i++){ scanf("%d%d",&x,&y); x=((ll)x+ans)%(n-1)+1; y=((ll)y+ans)%(n-1)+1; if (x>y) swap(x,y); y++; ans=(blg[x]<blg[y])?f[blg[x]+1][y]:0; for (j=x; j<=r[blg[x]] && j<=y; j++) ans=max(ans,qry(x,y,a[j])); printf("%d\n",ans); y--; } return 0; }
by lych
2016.2.27
相关文章推荐
- Java parseInt()和parseFloat()的用法
- Hadoop家族安装系列(2)——安装Mahout0.9框架
- delphi:斑马打印机ZPL指令打印中文及二维码,补充说明
- JAVASE基础 Item -- IO流综合练习
- Linux Redis 配置认证密码
- ReactiveCocoa框架到底是多强大
- Keepalived+Lvs+Mysql主主复制
- SpringMVC中使用-sqljdbc4.jar
- C#套接字使用
- 【漫画解读】HDFS存储原理
- 编写函数取得上一月的最后一天
- 浅析那些大型职业技术交流群是怎么被玩变质的?
- linux设置开机启动网关且配置静态IP
- 2015年度总结
- 关于python中send发送十六进制的方法
- centos的nginx安装
- Java基础知识(一)
- PHP会话安全
- PHP中如何判断一个字符串是否是合法的日期模式
- 《JavaScript高级程序设计》读书笔记(六):DOM