zoukankan      html  css  js  c++  java
  • BZOJ3489 A simple rmq problem

    Description

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

    Input

    第一行为两个整数N,MM是询问数,N是序列的长度(N<=100000M<=200000)

    第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

    再下面M行,每行两个整数xy

    询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<)

    l=min(x+lastans)mod n+1,(y+lastansmod n+1);

    r=max(x+lastans)mod n+1,(y+lastansmod n+1);

    Lastans表示上一个询问的答案,一开始lastans0

    Output

    一共M行,每行给出每个询问的答案。

    Sample Input

    10 10
    6 4 9 10 9 10 9 4 10 4
    3 8
    10 1
    3 4
    9 4
    8 1
    7 8
    2 9
    1 1
    7 3
    9 9

    Sample Output

    4
    10
    10
    0
    0
    10
    0
    4
    0
    4

    HINT

    注意出题人为了方便,input的第二行最后多了个空格。

    2015.6.24新加数据一组,但未重测

    Source

    by zhzqkkk

     正解:kd-tree

    解题报告:

      做这道题本来是为了试试可持久化线段树的,然而感觉好复杂。结果在网上突然看到一份博客,居然用的是kd-tree,当时就激动了。

      参考博客:http://trinklee.blog.163.com/blog/static/2381580602015422933539/

      这份博客讲的很清楚了,三维kd-tree。我们维护三个值,当前值的上一次出现位置,下一次出现位置。显然查询区间[l,r]时i满足当且仅当 last[num[i]]<l && next[num[i]]>r 时才需被计入贡献,满足要求。

      那么这样的查询显然是可以用kd-tree来做的。都是老套路了,想好怎么建了就跟我之前做的两道kd-tree题一样了。还没有插入操作了,还简单些了好吗

      代码如下:

      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 100011;
     21 int shu[MAXN];
     22 int n,m;
     23 int last[MAXN];
     24 int L[MAXN],R[MAXN];
     25 int root;
     26 int D;
     27 int ans;
     28 int cha[3][2];
     29 
     30 struct node{
     31     int l,r;
     32     int Min[3],Max[3],d[3];
     33     int num;
     34     int zhi;
     35 }a[MAXN];
     36 
     37 inline int getint()
     38 {
     39        int w=0,q=0;
     40        char c=getchar();
     41        while((c<'0' || c>'9') && c!='-') c=getchar();
     42        if (c=='-')  q=1, c=getchar();
     43        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     44        return q ? -w : w;
     45 }
     46 
     47 inline bool cmp(node q,node qq){
     48     for(int i=0;i<=2;i++)
     49     if(q.d[(D+i)%3]!=qq.d[(D+i)%3]) return (q.d[(D+i)%3]<qq.d[(i+D)%3]);
     50     return 1;
     51 }
     52 
     53 inline void update(int x){
     54     if(a[x].l) {
     55     for(int i=0;i<=2;i++) a[x].Min[i]=min(a[x].Min[i],a[a[x].l].Min[i]),a[x].Max[i]=max(a[x].Max[i],a[a[x].l].Max[i]);
     56     a[x].zhi=max(a[x].zhi,a[a[x].l].zhi);
     57     }
     58     if(a[x].r) {
     59     for(int i=0;i<=2;i++) a[x].Min[i]=min(a[x].Min[i],a[a[x].r].Min[i]),a[x].Max[i]=max(a[x].Max[i],a[a[x].r].Max[i]);
     60     a[x].zhi=max(a[x].zhi,a[a[x].r].zhi);
     61     }
     62 }
     63 
     64 inline int build_tree(int l,int r,int d){
     65     int mid=(l+r)/2; D=d;
     66     nth_element(a+l+1,a+mid+1,a+r+1,cmp);
     67     a[mid].zhi=a[mid].num;
     68     for(int i=0;i<=2;i++) a[mid].Min[i]=a[mid].Max[i]=a[mid].d[i];
     69 
     70     if(l!=mid) a[mid].l=build_tree(l,mid-1,(d+1)%3);
     71     if(mid!=r) a[mid].r=build_tree(mid+1,r,(d+1)%3);
     72     update(mid);
     73     return mid;
     74 }
     75 
     76 inline bool pan(int now){
     77     for(int i=0;i<=2;i++) {
     78     if(a[now].Max[i]<cha[i][0] || a[now].Min[i]>cha[i][1]) return false;
     79     }
     80     return true;
     81 }
     82 
     83 inline void query(int now) {
     84     if(a[now].zhi<ans) return ;//剪枝
     85     bool flag=true;
     86     for(int i=0;i<=2;i++) if(cha[i][0]>a[now].Min[i] || cha[i][1]<a[now].Max[i] ) { flag=false; break;}
     87     if(flag) { ans=max(ans,a[now].zhi); return ; }
     88     flag=true;
     89 
     90     for(int i=0;i<=2;i++) if(cha[i][0]>a[now].d[i] || cha[i][1]<a[now].d[i]) flag=false;
     91     if(flag) { ans=max(ans,a[now].num); }
     92     if(a[now].l && pan(a[now].l)) { query(a[now].l); }
     93     if(a[now].r && pan(a[now].r)) { query(a[now].r); }
     94 }
     95 
     96 inline void solve(){
     97     n=getint(); m=getint();
     98 
     99     for(int i=1;i<=n;i++) {
    100     shu[i]=getint();
    101     L[i]=last[shu[i]];
    102     last[shu[i]]=i;
    103     }
    104 
    105     for(int i=1;i<=n;i++) last[i]=n+1;
    106 
    107     for(int i=n;i>=1;i--) R[i]=last[shu[i]],last[shu[i]]=i;
    108 
    109     for(int i=1;i<=n;i++) {
    110     a[i].d[0]=i; a[i].d[1]=L[i]; a[i].d[2]=R[i];
    111     a[i].num=shu[i];
    112     }
    113 
    114     root=build_tree(1,n,0);
    115 
    116     int l,r,x,y;
    117     for(int i=1;i<=m;i++) {
    118     l=getint(); r=getint();
    119     x=(l+ans)%n+1; y=(r+ans)%n+1;
    120     if(x<y) l=x,r=y;
    121     else l=y,r=x;
    122 
    123     ans=0;
    124     cha[0][0]=l; cha[0][1]=r;
    125     cha[1][0]=0; cha[1][1]=l-1;
    126     cha[2][0]=r+1; cha[2][1]=n+1;
    127     query(root);
    128     printf("%d
    ",ans);
    129     }
    130 }
    131 
    132 int main()
    133 {
    134   solve();
    135   return 0;
    136 }
  • 相关阅读:
    数据库连接池实现
    Linux array_vpnc
    MVC小结
    Linux和Windows下 classpath 的差异
    无法删除DLL文件解决方法(转)
    电信工程管理方法
    常用设计思想
    MAX262使用说明
    基于FPGA的FIR滤波器(草稿)
    数字存储示波器(草稿)
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5595239.html
Copyright © 2011-2022 走看看