http://www.elijahqi.win/2018/01/12/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,但未重测
kd-tree可以暴力搞过 没有被卡死
题意:每次询问一个区间 然后求出这个区间内最大的那个数 据说标算是树套树什么的?
直接来做似乎不太好做 我们呢考虑一个数如何对某些区间产生影响 首先我们针对每个数求出他前一次数出现的位置 然后再求出他后一次出现的位置这个怎么求 根据zhx巨佬的方法 我可以o(n)小常数的搞出来记录b[]表示下标数值这个数上一次出现的位置 每次我上一个数出现的下一次就是我现在这个数 我这个数 上一次出现的位置就是b[] 然后就求出来了 接下来 我们将这个内容转成(i,j,k)一个三维空间的坐标第一维是 我当前这个数处在第几维度 j表示我这个数前一次出现是在哪里 k表示我这个数后一次出现是在哪里 针对一个询问区间L,R我们可以得知 我相当于需要求一个立方体内点权值的最大 那么kd-tree就可以搞了 我知道范围是L<=i<=R 并且j< L&k>R 这种情况的点才满足
#include
#include
#define N 110000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0;char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=gc();
return x;
}
int D,L,R,nxt[N],b[N],pre[N],a[N],n,m,ans,root;
struct node1{
int d[3],v;
int& operator[](int x) {return d[x];}
friend bool operator<(node1 a,node1 b){return a[D]int left,right,min[3],max[3],maxv;
}tree[N];
inline void update(int x){
int l=tree[x].left,r=tree[x].right;
tree[x].maxv=max(tree[x].maxv,max(tree[l].maxv,tree[r].maxv));
for (int i=0;i<3;++i) tree[x].min[i]=min(tree[x].min[i],min(tree[l].min[i],tree[r].min[i]));
for (int i=0;i<3;++i) tree[x].max[i]=max(tree[x].max[i],max(tree[l].max[i],tree[r].max[i]));
}
inline void build(int &x,int l,int r,int dim){
D=dim;int mid=l+r>>1;x=mid;nth_element(point+l,point+mid,point+r+1);tree[x].maxv=point[mid].v;
tree[x].x=point[mid];for (int i=0;i<3;++i) tree[x].min[i]=tree[x].max[i]=point[mid][i];
if (l1,(dim+1)%3);
if (r>mid) build(tree[x].right,mid+1,r,(dim+1)%3);update(x);
}
inline bool judge(node1 a){
if (a[0]0]>R) return 0;
if (a[1]>=L) return 0;if (a[2]<=R) return 0;
return 1;
}
inline bool judge1(int x){
if (tree[x].min[0]>R||tree[x].max[0]return 0;
if (tree[x].min[1]>=L) return 0;if (tree[x].max[2]<=R) return 0;
return 1;
}
inline void query(int x){
if (judge(tree[x].x)) if (tree[x].x.v>ans) ans=tree[x].x.v;int ansl=0,ansr=0;
if (tree[x].left) if (judge1(tree[x].left)) ansl=tree[tree[x].left].maxv;
if (tree[x].right) if (judge1(tree[x].right)) ansr=tree[tree[x].right].maxv;
if (ansl>ansr){
if (ansl>ans) query(tree[x].left);
if (ansr>ans) query(tree[x].right);
} else{
if (ansr>ans) query(tree[x].right);
if (ansl>ans) query(tree[x].left);
}
}
int main(){
freopen("bzoj3489.in","r",stdin);
n=read();m=read();for (int i=0;i<3;++i) tree[0].min[i]=inf;
for (int i=1;i<=n;++i) {
nxt[i]=n+1;a[i]=read();nxt[b[a[i]]]=i;pre[i]=b[a[i]];b[a[i]]=i;
}
// for (int i=1;i<=n;++i) printf("%d %d %d\n",a[i],pre[i],nxt[i]);
for (int i=1;i<=n;++i){point[i][0]=i;point[i][1]=pre[i];point[i][2]=nxt[i];point[i].v=a[i];}
build(root,1,n,0);int last_ans=0;
for (int i=1;i<=m;++i){
int x=read(),y=read();
L=min((x+last_ans)%n+1,(y+last_ans)%n+1);
R=max((x+last_ans)%n+1,(y+last_ans)%n+1);
ans=0;query(root);last_ans=ans;printf("%d\n",ans);
}
return 0;
}