Description
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
第一行为两个整数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
Solution
月考被踩爆了呀QAQ
考虑把每一个数字相同的前一个位置L[i]、后一个位置R[i]找出来,显然只有询问区间[l,r]满足L[i]<=l<=i<=r<=R[i]的时候a[i]才有可能被算,然后我就不会做了
题解说可以把(L[i],R[i],i)看成i这个点在三维空间中的坐标,那么我们实际上要找一个立方体中的最大值。这个可以树套树套树(雾)、树套树、树套堆、KD树来做,这里写了KD树的做法
注意KD树的剪枝,写了剪枝才不是暴力
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=200005;
struct treeNode {
int l,r,p[3],mn[3],mx[3],max,v;
bool operator <=(treeNode b) const {
treeNode a=*this;
return (a.p[0]<=b.p[0])&&(a.p[1]<=b.p[1])&&(a.p[2]<=b.p[2]);
}
} t[N];
int L[N],R[N],rec[N],a[N],D;
int ql,qr,ans;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void push_up(int x) {
rep(i,0,2) {
if (t[x].l) {
t[x].mx[i]=std:: max(t[x].mx[i],t[t[x].l].mx[i]);
t[x].mn[i]=std:: min(t[x].mn[i],t[t[x].l].mn[i]);
}
if (t[x].r) {
t[x].mx[i]=std:: max(t[x].mx[i],t[t[x].r].mx[i]);
t[x].mn[i]=std:: min(t[x].mn[i],t[t[x].r].mn[i]);
}
}
if (t[x].l) t[x].max=std:: max(t[x].max,t[t[x].l].max);
if (t[x].r) t[x].max=std:: max(t[x].max,t[t[x].r].max);
}
bool check(int x) {
if (t[x].mn[0]>=ql) return 0;
if (t[x].mx[2]<=qr) return 0;
if (t[x].mn[1]>qr||t[x].mx[1]<ql) return 0;
return 1;
}
void query(int now) {
if (t[now].p[0]<ql&&ql<=t[now].p[1]&&t[now].p[1]<=qr&&qr<t[now].p[2]) ans=std:: max(ans,t[now].v);
if (t[now].l) {
if (check(t[now].l)&&t[t[now].l].max>ans) query(t[now].l);
}
if (t[now].r) {
if (check(t[now].r)&&t[t[now].r].max>ans) query(t[now].r);
}
}
bool cmp(treeNode a,treeNode b) {
return a.p[D]<b.p[D];
}
int build(int l,int r,int d) {
int mid=(l+r)>>1; D=d;
std:: nth_element(t+l,t+mid,t+r+1,cmp);
rep(i,0,2) t[mid].mn[i]=t[mid].mx[i]=t[mid].p[i];
if (l<mid) t[mid].l=build(l,mid-1,(d+1)%3);
if (mid<r) t[mid].r=build(mid+1,r,(d+1)%3);
push_up(mid); return mid;
}
int main(void) {
// freopen("data.in","r",stdin);
int n=read(),m=read();
rep(i,1,n) a[i]=read();
rep(i,1,n) {
L[i]=rec[a[i]];
rec[a[i]]=i;
}
rep(i,1,n) rec[i]=n+1;
drp(i,n,1) {
R[i]=rec[a[i]];
rec[a[i]]=i;
}
rep(i,1,n) {
t[i].p[0]=t[i].mn[0]=t[i].mx[0]=L[i];
t[i].p[1]=t[i].mn[1]=t[i].mx[1]=i;
t[i].p[2]=t[i].mn[2]=t[i].mx[2]=R[i];
t[i].max=t[i].v=a[i];
}
int root=build(1,n,0);
for (int lastans=0,x,y;m--;) {
x=read(),y=read(),ql=(x+lastans)%n+1,qr=(y+lastans)%n+1;
if (qr<ql) std:: swap(ql,qr);
ans=0; query(root);
printf("%d\n", ans); lastans=ans;
}
return 0;
}