牛客练习赛81 小Q与彼岸花 (分块+可持久化01trie)
发布日期:2021-06-28 19:59:51
浏览次数:2
分类:技术文章
本文共 2513 字,大约阅读时间需要 8 分钟。
题意:
题解:因为这个题目是弱化以后的,正常的范围是5e4 . 看了官方题解去学习了一波可持久化01trie然后回来把这个题补完。可持久数据结构其实就是我们的数据结构的内容会不断发生变化,而我们还要查询以前的历史版本,比如某个区间的情况。
听名字可以听出来,可持久化01trie跟可持久化线段树差不多的效果,对于01字典树来说,可以指定查询 l − r l-r l−r 范围内的数组成的字典树。
但是针对于这个题目我们直接使用可持久化01trie进行维护,时间还是不能被允许的,所以说, 我们还需要去继续优化。
如何优化呢? 分块!
我们用数组 a n s [ x ] [ y ] ans[x][y] ans[x][y]预处理出来 块x到块y之间的区间任意两数的最大异或值。时间复杂度呢?
我们把数组分成大小为 n \sqrt{n} n的块,那么可以分成 ( n − 1 ) / n + 1 (n-1)/\sqrt{n}+1 (n−1)/n+1个块
所以预处理的复杂度为: O ( n ∗ n ∗ n ∗ l o g ( a m a x ) ) O(\sqrt{n}*\sqrt{n}*\sqrt{n}*log(a_{max}) ) O(n∗n∗n∗log(amax)) (类似于区间求解众数–强制在线) 应该没错。。。for(int i=1;i<=sumblocks;i++){ for(int j=i;j<=sumblocks;j++){ int nowmax=ans[i][j-1]; for(int k=(j-1)*sz+1;k<=min(n,j*sz);k++){ int res=query(rt[min(j*sz,n)],a[k],(i-1)*sz+1); nowmax=max(nowmax,res); } ans[i][j]=nowmax; }}
然后对于每次查询,如果l和r属于同一个块之间,那么我们直接暴力即可
那么如果不在同一个块呢,那么就跟最简单的分块一样了,先让最大值等于中间完整的块,然后我们暴力处理一下两边不全的块并不断更新最大值,然后返回最大值即可。代码:
#includeusing namespace std;const int maxn=5e6+10;int ans[300][300];int a[maxn],buck[maxn];int rt[maxn];int sz,idx;int trie[maxn*20][2];int max_id[maxn];void ins(int x,int pre,int now){ for(int i=12;i>=0;i--){ max_id[now]=x; int val=(a[x]>>i)&1; trie[now][val^1]=trie[pre][val^1]; trie[now][val]=++idx; now=idx; pre=trie[pre][val]; } max_id[now]=x;}int query(int root,int C,int L){ int p=root; for(int i=12;i>=0;i--){ int val=(C>>i)&1; if(max_id[trie[p][val^1]]>=L) p=trie[p][val^1]; else p=trie[p][val]; } return C^a[max_id[p]];}int get_block(int x){ return (x-1)/sz+1;}int sol(int l,int r){ int st=get_block(l); int ed=get_block(r); if(st==ed){ int imax=0; for(int i=l;i<=r;i++){ imax=max(imax,query(rt[r],a[i],l)); } return imax; } else{ int imax=ans[st+1][ed-1]; //cout<<"debug "< < >n>>m; sz=sqrt(n); for(int i=1;i<=n;i++){ cin>>a[i]; rt[i]=++idx; ins(i,rt[i-1],rt[i]); } int sumblocks=(n-1)/sz+1; for(int i=1;i<=sumblocks;i++){ for(int j=i;j<=sumblocks;j++){ int nowmax=ans[i][j-1]; for(int k=(j-1)*sz+1;k<=min(n,j*sz);k++){ int res=query(rt[min(j*sz,n)],a[k],(i-1)*sz+1); nowmax=max(nowmax,res); } ans[i][j]=nowmax; } } while(m--){ int l,r; cin>>l>>r; int xxx=sol(l,r); cout< <
转载地址:https://blog.csdn.net/xxxxxiao123/article/details/116167178 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年04月05日 17时49分02秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
nodeJS学习------拿到数据有RowDataPacket处理
2019-04-29
vue-cli3中引入less,scss等解决方案
2019-04-29
vue使用swiper插件修改左右箭头的默认样式
2019-04-29
微信小程序--拿到时间戳 转换 并绑定
2019-04-29
关于转换十位时间戳出现1970的问题
2019-04-29
【vue系列】在Vue项目中使用Sass-----(scss)安装详解,新手跟着做即可
2019-04-29
前端-给大家一个超级好用简单方便的图片压缩工具(网页在线)~
2019-04-29
前端html实现删除线的两种方法(下划线)css样式总结
2019-04-29
js根据ID获取输入框的值
2019-04-29
初学wx小程序在vscode上装什么插件
2019-04-29
(split盲点)javascript如何判断字符串中某个特定字符的个数
2019-04-29
axios请求头踩坑日记之-application/json
2019-04-29
vue-封装axios的GET请求
2019-04-29
javascript获取当前时间时间戳的几种方法
2019-04-29
微信小程序App()的作用与getApp()方法
2019-04-29
快速新建新建Vue项目(详细)
2019-04-29
vue项目启动自动开启浏览器
2019-04-29
Vue中 @表示的路径
2019-04-29