• [BZOJ3489] A simple rmq problem


    [BZOJ3489] A simple rmq problem

    Description

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

    Input

    第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
    第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
    再下面M行,每行两个整数x,y,询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):l=min((x+lastans)mod n+1,(y+lastans)mod n+1);r=max((x+lastans)mod n+1,(y+lastans)mod n+1);Lastans表示上一个询问的答案,一开始lastans为0

    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新加数据一组,2016.7.9放至40S,600M,但未重测

    试题分析

    遇到出现次数的题,首先应该想到一种套路叫做维护pre和nxt。
    那么这道题建立3维(pre,nxt,pos)的kd-tree后就简单了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
     
    inline int read(){
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int INF = 2147483600;
    const int MAXN = 310000;
     
    struct data{int mx[3],mn[3]; int d[3],val,Mx;}a[MAXN+1],b[MAXN+1];
    int D,N,M; int nxt[MAXN+1],vis[MAXN+1],pre[MAXN+1];
    int ls[MAXN+1],rs[MAXN+1]; int c[MAXN+1],d[MAXN+1];
     
    inline void update(int k,int x){
        a[k].Mx=max(a[k].Mx,a[x].Mx);
        for(int i=0;i<3;i++){
            a[k].mx[i]=max(a[k].mx[i],a[x].mx[i]);
            a[k].mn[i]=min(a[k].mn[i],a[x].mn[i]);
        } return ;
    } 
    inline bool cmp(data a,data b){return a.d[D]<b.d[D];}
    inline int build(int l,int r,int d){
        D=d; int mid=(l+r)>>1;
        nth_element(b+l,b+mid,b+r+1,cmp); a[mid]=b[mid]; a[mid].Mx=a[mid].val;
        for(int i=0;i<3;i++) a[mid].mx[i]=a[mid].mn[i]=a[mid].d[i];
        if(l<mid) ls[mid]=build(l,mid-1,(d+1)%3);
        if(r>mid) rs[mid]=build(mid+1,r,(d+1)%3);
        if(ls[mid]) update(mid,ls[mid]);
        if(rs[mid]) update(mid,rs[mid]);
        //cout<<mid<<":"<<a[mid].val<<" "<<a[mid].Mx<<" "<<ls[mid]<<" "<<rs[mid]<<endl;
        return mid;
    } int lastans;
    inline bool isquare(int rt,int l,int r){
        return l<=a[rt].mn[0]&&a[rt].mn[0]<=r&&l<=a[rt].mx[0]&&a[rt].mx[0]<=r&&a[rt].mx[1]<l&&a[rt].mn[1]<l&&a[rt].mn[2]>r&&a[rt].mx[2]>r;
    }
    inline bool inpoint(int rt,int l,int r){
        return l<=a[rt].d[0]&&a[rt].d[0]<=r&&a[rt].d[1]<l&&a[rt].d[2]>r;
    }
    inline void Query(int rt,int l,int r){
        if(a[rt].Mx<lastans||!rt) return ; //cout<<rt<<":"<<a[rt].d[0]<<" "<<a[rt].d[1]<<" "<<a[rt].Mx<<":"<<l<<" "<<r<<endl;
        if(a[rt].mn[0]>r||a[rt].mx[0]<l||a[rt].mn[1]>=l||a[rt].mx[2]<=r) return ;
        if(isquare(rt,l,r)) {lastans=max(lastans,a[rt].Mx); return ;}
        if(inpoint(rt,l,r)) lastans=max(lastans,a[rt].val); 
        if(a[ls[rt]].Mx>=a[rs[rt]].Mx){
            if(ls[rt]) Query(ls[rt],l,r);
            if(rs[rt]) Query(rs[rt],l,r);
        }
        else{
            if(rs[rt]) Query(rs[rt],l,r);
            if(ls[rt]) Query(ls[rt],l,r);
        } return ;
    }
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),M=read();
        for(int i=1;i<=N;i++) c[i]=d[i]=read(); sort(c+1,c+N+1);
        for(int i=1;i<=N;i++) b[i].val=d[i];
        for(int i=1;i<=N;i++) d[i]=lower_bound(c+1,c+N+1,d[i])-c;
        for(int i=1;i<=N;i++){
            nxt[vis[d[i]]]=i;
            pre[i]=vis[d[i]];
            vis[d[i]]=i;
        } for(int i=1;i<=N;i++) if(vis[i]) nxt[vis[i]]=N+1;
        for(int i=1;i<=N;i++) b[i].d[1]=pre[i],b[i].d[2]=nxt[i],b[i].d[0]=i;
        int root=build(1,N,0);
        while(M--){
            int l=(read()+lastans)%N+1,r=(read()+lastans)%N+1;
            if(l>r) swap(l,r);
            //cout<<l<<" "<<r<<endl; 
            lastans=0; Query(root,l,r); printf("%d
    ",lastans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    【Aizu
    【Aizu
    【OpenJ_Bailian
    leetcode-225-Implement Stack using Queues
    leetcode-219-Contains Duplicate II(使用set来判断长度为k+1的闭区间中有没有重复元素)
    leetcode-217-Contains Duplicate(使用排序来判断整个数组有没有重复元素)
    leetcode-840-Magic Squares In Grid
    leetcode-198-House Robber(动态规划)
    leetcode-191-Number of 1 Bits
    leetcode-189-Rotate Array
  • 原文地址:https://www.cnblogs.com/wxjor/p/9529048.html
Copyright © 2020-2023  润新知