【bzoj3489】 A simple rmq problem k-d树
由于某些原因,我先打了一个错误的树套树,后来打起了k−d。接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟......
对于一个数字ai,我们可以用一组三维坐标(i,pre,nxt)来表示,其中i表示该数字下标,pre表示在区间[1,i)中满足a[j]=a[i]的最大j,若不存在,则pre=0。nxt表示在区间(i,n]中满足a[j]=a[i]的最小j,若不存在,则nxt=n+1。
接着我们种一棵3-d树去存储这n个点。对于任意一个节点,需存储该节点的数字,以该节点为根的字数中最大的数字,每一维的最小值和最大值。对于一组询问[l,r],答案即为满足第一维在区间[l,r],第二维在区间[0,l),第三维在区间(r,n+1)中的所有点上的最大数字。在查询时,直接按照k−d的正常查询策略更新答案即可。
时间复杂度:O(nlogn+n53)
警告:若采用此方法,此题建议各位加一个微小的剪枝:假定当前所得到的最大答案为ans,若当前访问的字树中最大答案≤ans,直接跳过这棵字树即可。(借助该方法极限数据耗时从17.5s降低至1.4s)
1 #include<bits/stdc++.h> 2 #define M 210000 3 using namespace std; 4 int n,m,D,root; 5 struct kd{ 6 int a[3],max[3],min[3],now,ans,l,r; 7 kd(){a[0]=a[1]=a[2]=now=l=r=0;min[1]=min[2]=min[0]=12345678;} 8 kd(int xx,int yy,int zz,int kk){a[0]=xx;a[1]=yy;a[2]=zz;now=kk;} 9 friend bool operator <(kd a,kd b){ 10 return a.a[D]<b.a[D]; 11 } 12 }a[M]; 13 void upd(kd &x,kd &y){ 14 for(int i=0;i<3;i++) 15 x.max[i]=max(x.max[i],y.max[i]), 16 x.min[i]=min(x.min[i],y.min[i]); 17 } 18 inline int nx(int d){if(d==2) return 0; return d+1;} 19 void build(int &x,int l,int r,int d){ 20 if(l>r) return; int mid=(l+r)>>1; 21 D=d; nth_element(a+l,a+mid,a+r+1); x=mid; 22 for(int i=0;i<3;i++) a[x].max[i]=a[x].min[i]=a[x].a[i]; 23 build(a[x].l,l,mid-1,nx(d)); 24 build(a[x].r,mid+1,r,nx(d)); 25 upd(a[x],a[a[x].l]); upd(a[x],a[a[x].r]); 26 a[x].ans=max(a[x].now,max(a[a[x].l].ans,a[a[x].r].ans)); 27 } 28 int ans=0; 29 void query(int x,int l,int r){ 30 if(x==0||ans>=a[x].ans||r<a[x].min[0]||a[x].max[0]<l||l-1<a[x].min[1]||a[x].max[2]<r+1) return; 31 if(l<=a[x].min[0]&&a[x].max[0]<=r&&a[x].max[1]<l&&r<a[x].min[2]) 32 {ans=max(ans,a[x].ans); return;} 33 if(l<=a[x].a[0]&&a[x].a[0]<=r&&a[x].a[1]<l&&r<a[x].a[2]) ans=max(ans,a[x].now); 34 query(a[x].l,l,r); query(a[x].r,l,r); 35 } 36 int last[M]={0}; 37 int main(){ 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=n;i++){ 40 int x; scanf("%d",&x); 41 a[i].a[0]=i; a[i].now=x; 42 a[i].a[1]=last[x]; 43 a[last[x]].a[2]=i; 44 last[x]=i; 45 } 46 for(int i=1;i<=n;i++) if(a[i].a[2]==0) a[i].a[2]=n+1; 47 build(root,1,n,0); 48 while(m--){ 49 int x,y,l,r; scanf("%d%d",&x,&y); 50 l=(x+ans)%n+1; r=(y+ans)%n+1; if(l>r) swap(l,r); 51 ans=0; query(root,l,r); 52 printf("%d\n",ans); 53 } 54 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!