• 【bzoj3489】 A simple rmq problem k-d树


    由于某些原因,我先打了一个错误的树套树,后来打起了$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
    ",ans);
    53     }
    54 }    
  • 相关阅读:
    美国地质调研局USGS
    SAR 图像
    Matlab 之meshgrid, interp, griddata 用法和实例
    ENVISAT卫星及ASAR数据介绍
    ASP.NET Integration with IIS7
    ubuntu下C/C++基本开发环境的配置
    C++ Objects Part 1: Basic Object Memory Layout
    Socket Programming in Windows
    Memory Layout for Multiple and Virtual Inheritance
    Common Type System—Memory Layout at C# Online.NET
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/7930720.html
Copyright © 2020-2023  润新知