先考虑怎么样才能保证某个数只出现了一次。
对于序列中的某个数 a [ i ] a[i] a[i],我们求出上一个出现 a [ i ] a[i] a[i] 的位置为 p r e [ i ] pre[i] pre[i],下一个出现 a [ i ] a[i] a[i] 的位置为 n x t [ i ] nxt[i] nxt[i]。
那么当询问的 l l l、 r r r 满足 p r e [ i ] < l ⩽ i pre[i]<l\leqslant i pre[i]<l⩽i 且 i ⩽ r < n x t [ i ] i\leqslant r<nxt[i] i⩽r<nxt[i] 时,就会有 a [ i ] a[i] a[i] 这个数在区间 [ l , r ] [l,r] [l,r] 内只出现过一次。
所以我们对于每一个 i i i,把 ( i , p r e [ i ] , n x t [ i ] ) (i,pre[i],nxt[i]) (i,pre[i],nxt[i]) 当作一个三维坐标,用 k d − t r e e kd-tree kd−tree 维护即可。
T L E TLE TLE 了怎么办?
-
把 P o i n t Point Point 从结构体里拉出来。
-
把 c m p cmp cmp 按我的写法改一下
-
把 b u i l d build build 按我的写法改一下(直接把 m i d mid mid 当作当前点的编号)
-
在 q u e r y query query 时判断一下先去左儿子还是右儿子。
希望对你有帮助。
代码和注释如下:
#include<bits/stdc++.h>
#define N 200010
using namespace std;
int D;
struct Point
{
int num[3],val;
Point(){};
Point(const int x,const int y,const int z,const int vall)
{
num[0]=x,num[1]=y,num[2]=z,val=vall;
}
bool operator < (const Point &b) const
{
if(num[D]==b.num[D])
{
if(num[(D+1)%3]==b.num[(D+1)%3]) return num[(D+2)%3]<b.num[(D+2)%3];
return num[(D+1)%3]<b.num[(D+1)%3];
}
return num[D]<b.num[D];
}
}p[N];
struct Tree
{
int ch[2],maxn[3],minn[3],maxval;
Point x;
}t[N];
int n,m,a[N];
int root,node;
int last[N],pre[N],nxt[N];
int l,r,ans;
void up(const int u)
{
for(register int i=0;i<3;i++)
{
t[u].maxn[i]=t[u].minn[i]=t[u].x.num[i];
if(t[u].ch[0])
{
t[u].maxn[i]=max(t[u].maxn[i],t[t[u].ch[0]].maxn[i]);
t[u].minn[i]=min(t[u].minn[i],t[t[u].ch[0]].minn[i]);
}
if(t[u].ch[1])
{
t[u].maxn[i]=max(t[u].maxn[i],t[t[u].ch[1]].maxn[i]);
t[u].minn[i]=min(t[u].minn[i],t[t[u].ch[1]].minn[i]);
}
}
t[u].maxval=max(t[u].x.val,max(t[t[u].ch[0]].maxval,t[t[u].ch[1]].maxval));
}
void build(int &mid,const int l,const int r,const int d)
{
if(l>r) return;
mid=(l+r)>>1;
D=d,nth_element(p+l,p+mid,p+r+1);
t[mid].x=p[mid];
build(t[mid].ch[0],l,mid-1,(d+1)%3);
build(t[mid].ch[1],mid+1,r,(d+1)%3);
up(mid);
}
void query(const int u)
{
if(!u) return;
if(l<t[u].minn[1]||l>t[u].maxn[0]||r<t[u].minn[0]||r>t[u].maxn[2]||t[u].maxval<ans) return;
if(l>=t[u].maxn[1]&&l<=t[u].minn[0]&&r>=t[u].maxn[0]&&r<=t[u].minn[2])
{
ans=max(ans,t[u].maxval);
return;
}
if(l>=t[u].x.num[1]&&l<=t[u].x.num[0]&&r>=t[u].x.num[0]&&r<=t[u].x.num[2]) ans=max(ans,t[u].x.val);
query(t[u].ch[0]);
query(t[u].ch[1]);
}
inline void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
x*=f;
}
int main()
{
read(n),read(m);
for(register int i=1;i<=n;i++)
{
read(a[i]);
pre[i]=last[a[i]]+1;
nxt[last[a[i]]]=i-1;
last[a[i]]=i;
}
for(register int i=1;i<=n;i++)
p[i]=Point(i,pre[i],nxt[i]?nxt[i]:n,a[i]);
build(root,1,n,0);
while(m--)
{
read(l),read(r);
l=(l+ans)%n+1,r=(r+ans)%n+1;
ans=0;
if(l>r) swap(l,r);
query(root);
printf("%d\n",ans);
}
return 0;
}