[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\n",lastans);
    }
    return 0;
}

posted @ 2018-08-24 12:17  wxjor  阅读(167)  评论(0编辑  收藏  举报