Description
因爲是OJ上的題,就簡單點好了。給出一個長度爲n的序列,給出M個詢問:在[l,r]之間找到一個在這個區間裏只出現過一次的數,並且要求找的這個數儘可能大。如果找不到這樣的數,則直接輸出0。我會採取一些措施強制在線。
Input
第一行爲兩個整數N,M。M是詢問數,N是序列的長度(N<=100000,M<=200000)
第二行爲N個整數,描述這個序列{},其中所有1<=<=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行,每行給出每個詢問的答案。
Solution
KD-tree做法:
想法神仙,實現簡單。
設pre[i]爲上一個值爲的位置
設nxt[i]爲下一個值爲的位置
n個三維點,座標爲(pre[i],i,nxt[i]),權值爲。
插入到kd-tree中,直接暴力查,普通的判一下區間就行了。
要打一下ans的剪枝和左右兒子的判斷剪枝。
Code
#include<bits/stdc++.h>
using namespace std;
const double alpha=0.7;
struct pt{
int d[3],w;
void make(int x,int y,int z,int v){
d[0]=x,d[1]=y,d[2]=z,w=v;
}
}a[200010];
struct data{
int mx[3],mn[3],maxn,ls,rs,sz;
pt p;
}tree[200010];
int b[200010];
int c[200010];
int pre[200010];
int nxt[200010];
int stk[200010];
int nt[3]={1,2,0};
int n,m,ans,tot,word,top,rt,lans;
int operator <(pt u,pt v){
return u.d[word]<v.d[word];
}
int newnode(){
if(top) return stk[top--];
return ++tot;
}
void up(int x){
int l=tree[x].ls;
int r=tree[x].rs;
for(int i=0;i<3;i++){
tree[x].mx[i]=tree[x].mn[i]=tree[x].p.d[i];
if(l) tree[x].mx[i]=max(tree[x].mx[i],tree[l].mx[i]);
if(r) tree[x].mx[i]=max(tree[x].mx[i],tree[r].mx[i]);
if(l) tree[x].mn[i]=min(tree[x].mn[i],tree[l].mn[i]);
if(r) tree[x].mn[i]=min(tree[x].mn[i],tree[r].mn[i]);
}
tree[x].maxn=max(max(tree[l].maxn,tree[r].maxn),tree[x].p.w);
tree[x].sz=tree[l].sz+tree[r].sz+1;
}
int build(int l,int r,int wd){
if(l>r) return 0;
int mid=(l+r)>>1;
int x=newnode();
word=wd,nth_element(a+l,a+mid,a+r+1);
tree[x].p=a[mid];
tree[x].ls=build(l,mid-1,nt[wd]);
tree[x].rs=build(mid+1,r,nt[wd]);
up(x); return x;
}
bool in(int xl,int xr,int l,int r,int ql,int qr){
return (ql<=xl&&qr>=xr&&ql>=l&&qr<=r);
}
bool out(int xl,int xr,int l,int r,int ql,int qr){
return (ql>xr||qr<xl||ql<l||qr>r);
}
void query(int x,int ql,int qr){
if(x==0) return;
if(tree[x].maxn<=lans) return;
int ans=0,l=tree[x].ls,r=tree[x].rs;
if(in(tree[x].mn[0],tree[x].mx[0],tree[x].mx[1],tree[x].mn[2],ql,qr)) lans=max(lans,tree[x].maxn);
if(out(tree[x].mn[0],tree[x].mx[0],tree[x].mn[1],tree[x].mx[2],ql,qr)) return;
if(in(tree[x].p.d[0],tree[x].p.d[0],tree[x].p.d[1],tree[x].p.d[2],ql,qr)) lans=max(tree[x].p.w,lans);
if(tree[l].maxn>tree[r].maxn){
query(l,ql,qr);
query(r,ql,qr);
}
else{
query(r,ql,qr);
query(l,ql,qr);
}
}
int main(){
int x,y,l,r;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++){
pre[i]=c[b[i]]+1;
c[b[i]]=i;
}
for(int i=1;i<=n;i++) c[i]=n+1;
for(int i=n;i;i--){
nxt[i]=c[b[i]]-1;
c[b[i]]=i;
}
for(int i=1;i<=n;i++)
a[i].make(i,pre[i],nxt[i],b[i]);
rt=build(1,n,0);
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
l=min((x+lans)%n+1,(y+lans)%n+1);
r=max((x+lans)%n+1,(y+lans)%n+1);
lans=0,query(rt,l,r);
printf("%d\n",lans);
}
}