码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj3489】 A simple rmq problem k-d树

时间:2017-11-30 20:19:30      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:end   复杂度   upd   efi   复杂   最大数   names   节点   last   

由于某些原因,我先打了一个错误的树套树,后来打起了$k-d$。接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟......

对于一个数字$a_i$,我们可以用一组三维坐标$(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(n log n+n^\frac{5}{3})$

警告:若采用此方法,此题建议各位加一个微小的剪枝:假定当前所得到的最大答案为$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 }    

 

【bzoj3489】 A simple rmq problem k-d树

标签:end   复杂度   upd   efi   复杂   最大数   names   节点   last   

原文地址:http://www.cnblogs.com/xiefengze1/p/7930720.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!