BZOJ_3489_ A simple rmq problem_KDTree
BZOJ_3489_ A simple rmq problem_KDTree
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
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
10
10
0
0
10
0
4
0
4
HINT
注意出题人为了方便,input的第二行最后多了个空格。
2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测
设ai上一次出现的位置为pre[i],下一次出现的位置为nxt[i],则我们需要找一个ai最大的点,使得l<=i<=r,pre[i]<l,nxt[i]>r。
使用三维KDTree即可。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; #define N 100050 int ch[N][2],mx[N][3],mn[N][3],root,now,mxv[N],n,ans,m,tt[N]; #define ls ch[p][0] #define rs ch[p][1] #define _min(x,y) ((x)<(y)?(x):(y)) #define _max(x,y) ((x)>(y)?(x):(y)) #define _(x) (x==2?0:x+1) struct Point { int p[3],v; bool operator < (const Point &x) const { int t=_(now); if(p[now]==x.p[now]&&p[t]==x.p[t]) return p[_(t)]<x.p[_(t)]; if(p[now]==x.p[now]) return p[t]<x.p[t]; return p[now]<x.p[now]; } }a[N]; void pushup(int p,int x) { int i; for(i=0;i<3;i++) { mn[p][i]=_min(mn[p][i],mn[x][i]); mx[p][i]=_max(mx[p][i],mx[x][i]); } mxv[p]=_max(mxv[p],mxv[x]); } int build(int l,int r,int type) { int mid=(l+r)>>1; now=type; nth_element(a+l,a+mid,a+r+1); int i; for(i=0;i<3;i++) mn[mid][i]=mx[mid][i]=a[mid].p[i]; mxv[mid]=a[mid].v; if(l<mid) ch[mid][0]=build(l,mid-1,_(type)),pushup(mid,ch[mid][0]); if(r>mid) ch[mid][1]=build(mid+1,r,_(type)),pushup(mid,ch[mid][1]); return mid; } void query(int l,int r,int p) { if(!p||mxv[p]<=ans||mx[p][0]<l||mn[p][0]>r||mn[p][1]>=l||mx[p][2]<=r) return ; if(a[p].p[0]>=l&&a[p].p[0]<=r&&a[p].p[1]<l&&a[p].p[2]>r) ans=_max(ans,a[p].v); query(l,r,ls); query(l,r,rs); } int main() { scanf("%d%d",&n,&m); int i,x,y; for(i=1;i<=n;i++) { scanf("%d",&x); a[i].p[0]=i; a[i].p[1]=tt[x]; a[tt[x]].p[2]=i; tt[x]=i; a[i].v=x; } for(i=1;i<=n;i++) if(!a[i].p[2]) a[i].p[2]=n+1; root=build(1,n,0); for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); int l=min((x+ans)%n+1,(y+ans)%n+1),r=max((x+ans)%n+1,(y+ans)%n+1); ans=0; query(l,r,root); printf("%d\n",ans); } }