zoukankan      html  css  js  c++  java
  • 【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 }    
  • 相关阅读:
    yocto/bitbake 学习资源
    QEMU/KVM学习资源
    ubuntu 中创建和删除用户
    git 重命名本地和远程分支
    Ubuntu 上搭建 FTP 服务器
    gdb 常见用法
    git log 显示与特定文件相关的 commit 信息
    基于 qemu system mode 运行 arm 程序
    基于 qemu user mode 运行 aarch64 程序
    checking in(airport)
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/7930720.html
Copyright © 2011-2022 走看看