首页 > 代码库 > 【BZOJ3489】A simple rmq problem kd-tree
【BZOJ3489】A simple rmq problem kd-tree
【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
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,但未重测
题解:在[l,r]中只出现一次等价于:上一次出现的位置<l&&l<=这次出现的位置<=r&&下一次出现的位置>r。然后写个三维kd-tree就行了。
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define rep for(int i=0;i<3;i++)#define D1 ((D+1)%3)#define D2 ((D+2)%3)using namespace std;const int maxn=100010;int A,B,D,n,m,ans,root;int head[maxn],pre[maxn],next[maxn],buc[maxn],v[maxn];struct kd{ int v[3],sm[3],sn[3],ls,rs,ms,s; kd (){} kd (int a,int b,int c,int d){v[0]=sm[0]=sn[0]=a,v[1]=sm[1]=sn[1]=b,v[2]=sm[2]=sn[2]=c,s=ms=d,ls=rs=0;} int & operator [] (int a) {return v[a];} bool operator < (kd a) const { return (v[D]==a[D])?((v[D1]==a[D1])?(v[D2]==a[D2]):(v[D1]<a[D1])):(v[D]<a[D]); }};kd t[maxn];int rd(){ int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f;}void pushup(int x,int y){ rep t[x].sm[i]=max(t[x].sm[i],t[y].sm[i]),t[x].sn[i]=min(t[x].sn[i],t[y].sn[i]); t[x].ms=max(t[x].ms,t[y].ms);}int build(int l,int r,int d){ if(l>r) return 0; D=d; int mid=l+r>>1; nth_element(t+l,t+mid,t+r+1); t[mid].ls=build(l,mid-1,(d+1)%3),t[mid].rs=build(mid+1,r,(d+1)%3); if(t[mid].ls) pushup(mid,t[mid].ls); if(t[mid].rs) pushup(mid,t[mid].rs); return mid;}int check(int x){ if(t[x].ms<=ans||t[x].sm[0]<A||t[x].sn[0]>B||t[x].sn[1]>=A||t[x].sm[2]<=B) return 0; return 1;}void query(int x){ if(!x||!check(x)) return ; if(t[x][0]>=A&&t[x][0]<=B&&t[x][1]<A&&t[x][2]>B&&t[x].s>ans) ans=t[x].s; query(t[x].ls),query(t[x].rs);}int main(){ n=rd(),m=rd(); int i; for(i=1;i<=n;i++) { v[i]=rd(),pre[i]=head[v[i]]; if(head[v[i]]) next[head[v[i]]]=i; head[v[i]]=i; } for(i=1;i<=n;i++) if(!next[i]) next[i]=n+1; for(i=1;i<=n;i++) t[i]=kd(i,pre[i],next[i],v[i]); root=build(1,n,0); for(i=1;i<=m;i++) { A=(ans+rd())%n+1,B=(ans+rd())%n+1; if(A>B) swap(A,B); ans=0,query(root); printf("%d\n",ans); } return 0;}
【BZOJ3489】A simple rmq problem kd-tree
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。