因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
因为是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
一共M行,每行给出每个询问的答案。
注意出题人为了方便,input的第二行最后多了个空格。
2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测
by zhzqkkk
题解:KD-tree
这道题应该标算不是KD-tree,ATP大神说它写的是主席树套树,好高端,不会啊,呜呜呜。。。
于是就直接上KD-tree了。
对于每个位置,我们维护三个维度为该位置,与该位置同权值的前一个数的位置和后一个数的位置(x,y,z)
我们要找的数是所有满足
x>=l&&x<=r
y
那么直接用KD-tree统计答案即可。
#include
#include
#include
#include
#define N 200003
using namespace std;
int n,m,cmpd,root,pre[N],next[N],point[N],ans,lastans,x,y,val[N];
struct data {
int d[3],mx[3],mn[3],val,maxn;
int l,r;
}tr[N];
int tmp[10][10];
int cmp(data a,data b)
{
return a.d[cmpd]mid) tr[mid].r=build(mid+1,r,d+1);
update(mid);
return mid;
}
int check(int now)
{
if (tr[now].mx[0]y) return 0;
if (tr[now].mn[1]>=x) return 0;
if (tr[now].mx[2]<=y) return 0;
return 1;
}
void query(int now)
{
if (tr[now].d[0]>=x&&tr[now].d[0]<=y&&tr[now].d[1]y)
ans=max(ans,tr[now].val);
int l=tr[now].l; int r=tr[now].r;
if (l&&tr[l].maxn>ans)
if (check(l)) query(l);
if (r&&tr[r].maxn>ans)
if (check(r)) query(r);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&val[i]);
memset(point,0,sizeof(point));
for (int i=1;i<=n;i++)
pre[i]=point[val[i]],point[val[i]]=i;
for (int i=1;i<=n;i++) point[i]=n+1;
for (int i=n;i>=1;i--)
next[i]=point[val[i]],point[val[i]]=i;
for (int i=1;i<=n;i++)
tr[i].d[0]=i,tr[i].d[1]=pre[i],tr[i].d[2]=next[i],tr[i].val=tr[i].maxn=val[i];
root=build(1,n,0);
lastans=0;
for (int i=1;i<=m;i++) {
scanf("%d%d",&x,&y);
x=(x+lastans)%n+1;
y=(y+lastans)%n+1;
if (x>y) swap(x,y);
ans=0;
query(root);
printf("%d\n",ans);
lastans=ans;
}
}