[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;
}
你——悟到了么?