1. 程式人生 > >【BZOJ3489】A simple rmq problem kd-tree

【BZOJ3489】A simple rmq problem kd-tree

while 長度 {} per tput amp 可能 ans bzoj3489

【BZOJ3489】A simple rmq problem

Description

因為是OJ上的題,就簡單點好了。給出一個長度為n的序列,給出M個詢問:在[l,r]之間找到一個在這個區間裏只出現過一次的數,並且要求找的這個數盡可能大。如果找不到這樣的數,則直接輸出0。我會采取一些措施強制在線。

Input

第一行為兩個整數N,MM是詢問數,N是序列的長度(N<=100000M<=200000)

第二行為N個整數,描述這個序列{ai},其中所有1<=ai<=N

再下面M行,每行兩個整數xy

詢問區間[l,r]由下列規則產生(OIER都知道是怎樣的吧>_<)

l=min(x+lastans)mod n+1,(y+lastansmod n+1);

r=max(x+lastans)mod n+1,(y+lastansmod n+1);

Lastans表示上一個詢問的答案,一開始lastans0

Output

一共M行,每行給出每個詢問的答案。

Sample Input

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9

Sample Output

4
10
10
0
0
10
0
4
0
4

HINT

註意出題人為了方便,input的第二行最後多了個空格。

2015.6.24新加數據一組,2016.7.9放至40S,600M,但未重測

題解:在[l,r]中只出現一次等價於:上一次出現的位置<l&&l<=這次出現的位置<=r&&下一次出現的位置>r。然後寫個三維kd-tree就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep for(int i=0;i<3;i++)
#define D1 ((D+1)%3)
#define D2 ((D+2)%3)
using namespace std;
const int maxn=100010;
int A,B,D,n,m,ans,root;
int head[maxn],pre[maxn],next[maxn],buc[maxn],v[maxn];
struct kd
{
	int v[3],sm[3],sn[3],ls,rs,ms,s;
	kd (){}
	kd (int a,int b,int c,int d){v[0]=sm[0]=sn[0]=a,v[1]=sm[1]=sn[1]=b,v[2]=sm[2]=sn[2]=c,s=ms=d,ls=rs=0;}
	int	& operator [] (int a)	{return v[a];}
	bool operator < (kd a)	const
	{
		return (v[D]==a[D])?((v[D1]==a[D1])?(v[D2]==a[D2]):(v[D1]<a[D1])):(v[D]<a[D]);
	}
};
kd t[maxn];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void pushup(int x,int y)
{
	rep t[x].sm[i]=max(t[x].sm[i],t[y].sm[i]),t[x].sn[i]=min(t[x].sn[i],t[y].sn[i]);
	t[x].ms=max(t[x].ms,t[y].ms);
}
int build(int l,int r,int d)
{
	if(l>r)	return 0;
	D=d;
	int mid=l+r>>1;
	nth_element(t+l,t+mid,t+r+1);
	t[mid].ls=build(l,mid-1,(d+1)%3),t[mid].rs=build(mid+1,r,(d+1)%3);
	if(t[mid].ls)	pushup(mid,t[mid].ls);
	if(t[mid].rs)	pushup(mid,t[mid].rs);
	return mid;
}
int check(int x)
{
	if(t[x].ms<=ans||t[x].sm[0]<A||t[x].sn[0]>B||t[x].sn[1]>=A||t[x].sm[2]<=B)	return 0;
	return 1;
}
void query(int x)
{
	if(!x||!check(x))	return ;
	if(t[x][0]>=A&&t[x][0]<=B&&t[x][1]<A&&t[x][2]>B&&t[x].s>ans)	ans=t[x].s;
	query(t[x].ls),query(t[x].rs);
}
int main()
{
	n=rd(),m=rd();
	int i;
	for(i=1;i<=n;i++)
	{
		v[i]=rd(),pre[i]=head[v[i]];
		if(head[v[i]])	next[head[v[i]]]=i;
		head[v[i]]=i;
	}
	for(i=1;i<=n;i++)	if(!next[i])	next[i]=n+1;
	for(i=1;i<=n;i++)	t[i]=kd(i,pre[i],next[i],v[i]);
	root=build(1,n,0);
	for(i=1;i<=m;i++)
	{
		A=(ans+rd())%n+1,B=(ans+rd())%n+1;
		if(A>B)	swap(A,B);
		ans=0,query(root);
		printf("%d\n",ans);
	}
	return 0;
}

【BZOJ3489】A simple rmq problem kd-tree