zoukankan      html  css  js  c++  java
  • 【BZOJ3489】A simple rmq problem【kd树】

    题意

      给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

    分析

      预处理出pre[i],nxt[i]分别代表左边离它最近的相同数字的坐标,nxt[i]代表右边离它最近的相同数组的坐标。那么我们每次查询在[l,r]内,找出一个最大的数字且它的pre[i]<l,nxt[i]>r。我们如何用kd树解决这个问题呢?我们用三维的kd树来处理,第一维为下标i,第二维为pre[i],第三维为nxt[i],val为它本身的值。那么我们每次查询都是在一个长方体内查询最大的val就可以了。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <iostream>
      5 
      6 using namespace std;
      7 const int maxn=1e5+100;
      8 const int INF=2147000000;
      9 int a[maxn],pre[maxn],nxt[maxn],last[maxn];
     10 struct kdNode{
     11     int x[3],mnn[3],mxn[3];
     12     int lc,rc;
     13     int val,maxv;
     14 }p[maxn],q;
     15 int n,m,cmpNo,root;
     16 int cmp(kdNode a,kdNode b){
     17     return a.x[cmpNo]<b.x[cmpNo];
     18 }
     19 void maintain(int o){
     20     int l=p[o].lc,r=p[o].rc;
     21     for(int i=0;i<3;i++){
     22         p[o].mnn[i]=min(min(p[l].mnn[i],p[r].mnn[i]),p[o].x[i]);
     23         p[o].mxn[i]=max(max(p[l].mxn[i],p[r].mxn[i]),p[o].x[i]);
     24     }
     25     p[o].maxv=max(max(p[l].maxv,p[r].maxv),p[o].val);
     26 }
     27 void build(int&o,int l,int r,int d){
     28     if(l>r){
     29         o=0;
     30         return;
     31     }
     32     int m=l+(r-l)/2;
     33     cmpNo=d,o=m;
     34     nth_element(p+l,p+m,p+r+1,cmp);
     35     build(p[o].lc,l,m-1,(d+1)%3);
     36     build(p[o].rc,m+1,r,(d+1)%3);
     37     maintain(o);
     38 }
     39 int ans,l,r;//查询l<=x[0]<=r,x[1]<=l,x[2]>=r 空间内的最大值,这时候的kd树感觉就是高维线段树
     40 bool all(int o){
     41     if(p[o].mxn[0]<=r&&p[o].mnn[0]>=l&&p[o].mxn[1]<l&&p[o].mnn[2]>r)
     42         return true;
     43     return false;
     44 }
     45 bool have(int o){
     46     if(p[o].mnn[0]<=r&&p[o].mxn[0]>=l&&p[o].mnn[1]<l&&p[o].mxn[2]>r)
     47         return true;
     48     return false;
     49 }
     50 
     51 void query(int o,int d){
     52     if(!o){
     53         return;
     54     }
     55     if(all(o)){
     56         ans=max(ans,p[o].maxv);
     57         return;
     58     }
     59   //  ans=max(ans,p[o].val);
     60     if(p[o].x[0]<=r&&p[o].x[0]>=l&&p[o].x[1]<l&&p[o].x[2]>r)
     61         ans=max(ans,p[o].val);
     62 
     63     int lc=p[o].lc,rc=p[o].rc;
     64     if(p[lc].maxv<p[rc].maxv){
     65         if(all(rc)){
     66             ans=max(ans,p[rc].maxv);
     67         }else if(have(rc)){
     68             query(rc,(d+1)%3);
     69         }
     70         if(ans<p[lc].maxv){
     71             if(all(lc))
     72                 ans=max(ans,p[lc].maxv);
     73             else if(have(lc))
     74                 query(lc,(d+1)%3);
     75         }
     76     }else{
     77         if(all(lc)){
     78             ans=max(ans,p[lc].maxv);
     79         }else if(have(lc)){
     80             query(lc,(d+1)%3);
     81         }
     82         if(ans<p[rc].maxv){
     83             if(all(rc))
     84                 ans=max(ans,p[rc].maxv);
     85             else if(have(rc))
     86                 query(rc,(d+1)%3);
     87         }
     88     }
     89 }
     90 
     91 int main(){
     92     scanf("%d%d",&n,&m);
     93     for(int i=1;i<=n;i++){
     94         scanf("%d",&a[i]);
     95         if(last[a[i]])
     96             pre[i]=last[a[i]];
     97         else
     98             pre[i]=0;
     99         last[a[i]]=i;
    100     }
    101     memset(last,0,sizeof(last));
    102     for(int i=n;i>=1;i--){
    103         if(last[a[i]])
    104             nxt[i]=last[a[i]];
    105         else
    106             nxt[i]=n+1;
    107         last[a[i]]=i;
    108     }
    109 
    110     for(int i=1;i<=n;i++){
    111         p[i].x[0]=i;
    112         p[i].x[1]=pre[i];
    113         p[i].x[2]=nxt[i];
    114         p[i].val=a[i];
    115         //printf("%d %d %d
    ",p[i].x[0],p[i].x[1],p[i].x[2]);
    116     }
    117     for(int i=0;i<3;i++){
    118         p[0].mnn[i]=INF;
    119         p[0].mxn[i]=-INF;
    120     }
    121 
    122     build(root,1,n,0);
    123     int lastans=0;
    124     for(int i=1;i<=m;i++){
    125         int L,R;
    126         scanf("%d%d",&L,&R);
    127         l=min((L+lastans)%n+1,(R+lastans)%n+1);
    128         r=max((L+lastans)%n+1,(R+lastans)%n+1);
    129        // printf("%d %d
    ",l,r);
    130         ans=0;
    131         query(root,0);
    132         printf("%d
    ",ans);
    133         lastans=ans;
    134     }
    135 return 0;
    136 }
    View Code
  • 相关阅读:
    Intersection Observer 观察元素何时进入或退出浏览器的视口
    JS防抖函数、节流函数工具类封装
    页面刷新时,如何保持原有vuex中的state信息
    vue具名插槽、作用域插槽的新写法
    vue-cli3+工具中,配置路径别名(vue.config.js)
    基于Vue-SSR优化方案归纳总结
    React组件设计:重新认识受控与非受控组件
    如何用 JavaScript 实现一个数组惰性求值库
    原生 js 中应该禁止出现的写法,以提高代码效率和安全性
    Javascript 实践中的命令模式
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/10023741.html
Copyright © 2011-2022 走看看