题意
给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
分析
预处理出pre[i],nxt[i]分别代表左边离它最近的相同数字的坐标,nxt[i]代表右边离它最近的相同数组的坐标。那么我们每次查询在[l,r]内,找出一个最大的数字且它的pre[i]<l,nxt[i]>r。我们如何用kd树解决这个问题呢?我们用三维的kd树来处理,第一维为下标i,第二维为pre[i],第三维为nxt[i],val为它本身的值。那么我们每次查询都是在一个长方体内查询最大的val就可以了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 const int maxn=1e5+100; 8 const int INF=2147000000; 9 int a[maxn],pre[maxn],nxt[maxn],last[maxn]; 10 struct kdNode{ 11 int x[3],mnn[3],mxn[3]; 12 int lc,rc; 13 int val,maxv; 14 }p[maxn],q; 15 int n,m,cmpNo,root; 16 int cmp(kdNode a,kdNode b){ 17 return a.x[cmpNo]<b.x[cmpNo]; 18 } 19 void maintain(int o){ 20 int l=p[o].lc,r=p[o].rc; 21 for(int i=0;i<3;i++){ 22 p[o].mnn[i]=min(min(p[l].mnn[i],p[r].mnn[i]),p[o].x[i]); 23 p[o].mxn[i]=max(max(p[l].mxn[i],p[r].mxn[i]),p[o].x[i]); 24 } 25 p[o].maxv=max(max(p[l].maxv,p[r].maxv),p[o].val); 26 } 27 void build(int&o,int l,int r,int d){ 28 if(l>r){ 29 o=0; 30 return; 31 } 32 int m=l+(r-l)/2; 33 cmpNo=d,o=m; 34 nth_element(p+l,p+m,p+r+1,cmp); 35 build(p[o].lc,l,m-1,(d+1)%3); 36 build(p[o].rc,m+1,r,(d+1)%3); 37 maintain(o); 38 } 39 int ans,l,r;//查询l<=x[0]<=r,x[1]<=l,x[2]>=r 空间内的最大值,这时候的kd树感觉就是高维线段树 40 bool all(int o){ 41 if(p[o].mxn[0]<=r&&p[o].mnn[0]>=l&&p[o].mxn[1]<l&&p[o].mnn[2]>r) 42 return true; 43 return false; 44 } 45 bool have(int o){ 46 if(p[o].mnn[0]<=r&&p[o].mxn[0]>=l&&p[o].mnn[1]<l&&p[o].mxn[2]>r) 47 return true; 48 return false; 49 } 50 51 void query(int o,int d){ 52 if(!o){ 53 return; 54 } 55 if(all(o)){ 56 ans=max(ans,p[o].maxv); 57 return; 58 } 59 // ans=max(ans,p[o].val); 60 if(p[o].x[0]<=r&&p[o].x[0]>=l&&p[o].x[1]<l&&p[o].x[2]>r) 61 ans=max(ans,p[o].val); 62 63 int lc=p[o].lc,rc=p[o].rc; 64 if(p[lc].maxv<p[rc].maxv){ 65 if(all(rc)){ 66 ans=max(ans,p[rc].maxv); 67 }else if(have(rc)){ 68 query(rc,(d+1)%3); 69 } 70 if(ans<p[lc].maxv){ 71 if(all(lc)) 72 ans=max(ans,p[lc].maxv); 73 else if(have(lc)) 74 query(lc,(d+1)%3); 75 } 76 }else{ 77 if(all(lc)){ 78 ans=max(ans,p[lc].maxv); 79 }else if(have(lc)){ 80 query(lc,(d+1)%3); 81 } 82 if(ans<p[rc].maxv){ 83 if(all(rc)) 84 ans=max(ans,p[rc].maxv); 85 else if(have(rc)) 86 query(rc,(d+1)%3); 87 } 88 } 89 } 90 91 int main(){ 92 scanf("%d%d",&n,&m); 93 for(int i=1;i<=n;i++){ 94 scanf("%d",&a[i]); 95 if(last[a[i]]) 96 pre[i]=last[a[i]]; 97 else 98 pre[i]=0; 99 last[a[i]]=i; 100 } 101 memset(last,0,sizeof(last)); 102 for(int i=n;i>=1;i--){ 103 if(last[a[i]]) 104 nxt[i]=last[a[i]]; 105 else 106 nxt[i]=n+1; 107 last[a[i]]=i; 108 } 109 110 for(int i=1;i<=n;i++){ 111 p[i].x[0]=i; 112 p[i].x[1]=pre[i]; 113 p[i].x[2]=nxt[i]; 114 p[i].val=a[i]; 115 //printf("%d %d %d\n",p[i].x[0],p[i].x[1],p[i].x[2]); 116 } 117 for(int i=0;i<3;i++){ 118 p[0].mnn[i]=INF; 119 p[0].mxn[i]=-INF; 120 } 121 122 build(root,1,n,0); 123 int lastans=0; 124 for(int i=1;i<=m;i++){ 125 int L,R; 126 scanf("%d%d",&L,&R); 127 l=min((L+lastans)%n+1,(R+lastans)%n+1); 128 r=max((L+lastans)%n+1,(R+lastans)%n+1); 129 // printf("%d %d\n",l,r); 130 ans=0; 131 query(root,0); 132 printf("%d\n",ans); 133 lastans=ans; 134 } 135 return 0; 136 }
【BZOJ3489】A simple rmq problem【kd树】
原文:https://www.cnblogs.com/LQLlulu/p/10023741.html